blob: f0cb75ac46f36740ffb963da2fbb59767b151378 [file] [log] [blame]
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001// Copyright 2011 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000035#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000036#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037#include "compiler.h"
38#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000039#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000041#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000042#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000043#include "global-handles.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044#include "jsregexp.h"
danno@chromium.org40cb8782011-05-25 07:58:50 +000045#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000046#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000047#include "liveobjectlist-inl.h"
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000048#include "misc-intrinsics.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000049#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000050#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000051#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000052#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000053#include "scopeinfo.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000054#include "smart-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000055#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000056#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000057#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000058#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000059
kasperl@chromium.org71affb52009-05-26 05:44:31 +000060namespace v8 {
61namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000062
63
ager@chromium.org3e875802009-06-29 08:26:34 +000064#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000065 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000066
67// Cast the given object to a value of the specified type and store
68// it in a variable with the given name. If the object is not of the
69// expected type call IllegalOperation and return.
70#define CONVERT_CHECKED(Type, name, obj) \
71 RUNTIME_ASSERT(obj->Is##Type()); \
72 Type* name = Type::cast(obj);
73
74#define CONVERT_ARG_CHECKED(Type, name, index) \
75 RUNTIME_ASSERT(args[index]->Is##Type()); \
76 Handle<Type> name = args.at<Type>(index);
77
kasper.lundbd3ec4e2008-07-09 11:06:54 +000078// Cast the given object to a boolean and store it in a variable with
79// the given name. If the object is not a boolean call IllegalOperation
80// and return.
81#define CONVERT_BOOLEAN_CHECKED(name, obj) \
82 RUNTIME_ASSERT(obj->IsBoolean()); \
83 bool name = (obj)->IsTrue();
84
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000085// Cast the given argument to a Smi and store its value in an int variable
86// with the given name. If the argument is not a Smi call IllegalOperation
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000087// and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000088#define CONVERT_SMI_ARG_CHECKED(name, index) \
89 RUNTIME_ASSERT(args[index]->IsSmi()); \
90 int name = args.smi_at(index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000091
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000092// Cast the given argument to a double and store it in a variable with
93// the given name. If the argument is not a number (as opposed to
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000094// the number not-a-number) call IllegalOperation and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000095#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
96 RUNTIME_ASSERT(args[index]->IsNumber()); \
97 double name = args.number_at(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000098
99// Call the specified converter on the object *comand store the result in
100// a variable of the specified type with the given name. If the
101// object is not a Number call IllegalOperation and return.
102#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
103 RUNTIME_ASSERT(obj->IsNumber()); \
104 type name = NumberTo##Type(obj);
105
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000106
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000107MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
108 JSObject* boilerplate) {
109 StackLimitCheck check(isolate);
110 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000111
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000112 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000113 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000114 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000115 if (!maybe_result->ToObject(&result)) return maybe_result;
116 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000117 JSObject* copy = JSObject::cast(result);
118
119 // Deep copy local properties.
120 if (copy->HasFastProperties()) {
121 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000122 for (int i = 0; i < properties->length(); i++) {
123 Object* value = properties->get(i);
124 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000125 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000126 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000127 if (!maybe_result->ToObject(&result)) return maybe_result;
128 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000129 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000130 }
131 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000132 int nof = copy->map()->inobject_properties();
133 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000134 Object* value = copy->InObjectPropertyAt(i);
135 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000136 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000137 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000138 if (!maybe_result->ToObject(&result)) return maybe_result;
139 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000140 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000141 }
142 }
143 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000144 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000145 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000146 if (!maybe_result->ToObject(&result)) return maybe_result;
147 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000148 FixedArray* names = FixedArray::cast(result);
149 copy->GetLocalPropertyNames(names, 0);
150 for (int i = 0; i < names->length(); i++) {
151 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000152 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000153 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000154 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000155 // Only deep copy fields from the object literal expression.
156 // In particular, don't try to copy the length attribute of
157 // an array.
158 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000159 Object* value =
160 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000161 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000162 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000163 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000164 if (!maybe_result->ToObject(&result)) return maybe_result;
165 }
166 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000167 // Creating object copy for literals. No strict mode needed.
168 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000169 if (!maybe_result->ToObject(&result)) return maybe_result;
170 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000171 }
172 }
173 }
174
175 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000176 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000177 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000178 switch (copy->GetElementsKind()) {
179 case JSObject::FAST_ELEMENTS: {
180 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000181 if (elements->map() == heap->fixed_cow_array_map()) {
182 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000183#ifdef DEBUG
184 for (int i = 0; i < elements->length(); i++) {
185 ASSERT(!elements->get(i)->IsJSObject());
186 }
187#endif
188 } else {
189 for (int i = 0; i < elements->length(); i++) {
190 Object* value = elements->get(i);
191 if (value->IsJSObject()) {
192 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000193 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
194 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000195 if (!maybe_result->ToObject(&result)) return maybe_result;
196 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000197 elements->set(i, result);
198 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000199 }
200 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000201 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000202 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000203 case JSObject::DICTIONARY_ELEMENTS: {
204 NumberDictionary* element_dictionary = copy->element_dictionary();
205 int capacity = element_dictionary->Capacity();
206 for (int i = 0; i < capacity; i++) {
207 Object* k = element_dictionary->KeyAt(i);
208 if (element_dictionary->IsKey(k)) {
209 Object* value = element_dictionary->ValueAt(i);
210 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000211 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000212 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
213 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000214 if (!maybe_result->ToObject(&result)) return maybe_result;
215 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000216 element_dictionary->ValueAtPut(i, result);
217 }
218 }
219 }
220 break;
221 }
222 default:
223 UNREACHABLE();
224 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000225 }
226 return copy;
227}
228
229
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000230RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000231 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000232 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000233}
234
235
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000236RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000237 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000238 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000239}
240
241
ager@chromium.org236ad962008-09-25 09:45:57 +0000242static Handle<Map> ComputeObjectLiteralMap(
243 Handle<Context> context,
244 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000245 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000246 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000247 int properties_length = constant_properties->length();
248 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000249 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000250 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000251 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000252 for (int p = 0; p != properties_length; p += 2) {
253 Object* key = constant_properties->get(p);
254 uint32_t element_index = 0;
255 if (key->IsSymbol()) {
256 number_of_symbol_keys++;
257 } else if (key->ToArrayIndex(&element_index)) {
258 // An index key does not require space in the property backing store.
259 number_of_properties--;
260 } else {
261 // Bail out as a non-symbol non-index key makes caching impossible.
262 // ASSERT to make sure that the if condition after the loop is false.
263 ASSERT(number_of_symbol_keys != number_of_properties);
264 break;
265 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000266 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000267 // If we only have symbols and array indices among keys then we can
268 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000269 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000270 if ((number_of_symbol_keys == number_of_properties) &&
271 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000272 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000273 Handle<FixedArray> keys =
274 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000275 if (number_of_symbol_keys > 0) {
276 int index = 0;
277 for (int p = 0; p < properties_length; p += 2) {
278 Object* key = constant_properties->get(p);
279 if (key->IsSymbol()) {
280 keys->set(index++, key);
281 }
282 }
283 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000284 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000285 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000286 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000287 }
288 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000289 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000290 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000291 Handle<Map>(context->object_function()->initial_map()),
292 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000293}
294
295
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000296static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000297 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000298 Handle<FixedArray> literals,
299 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000300
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000301
302static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000303 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000304 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000305 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000306 bool should_have_fast_elements,
307 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000308 // Get the global context from the literals array. This is the
309 // context in which the function was created and we use the object
310 // function from this context to create the object literal. We do
311 // not use the object function from the current global context
312 // because this might be the object function from another context
313 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000314 Handle<Context> context =
315 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
316
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000317 // In case we have function literals, we want the object to be in
318 // slow properties mode for now. We don't go in the map cache because
319 // maps with constant functions can't be shared if the functions are
320 // not the same (which is the common case).
321 bool is_result_from_cache = false;
322 Handle<Map> map = has_function_literal
323 ? Handle<Map>(context->object_function()->initial_map())
324 : ComputeObjectLiteralMap(context,
325 constant_properties,
326 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000327
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000328 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000329
330 // Normalize the elements of the boilerplate to save space if needed.
331 if (!should_have_fast_elements) NormalizeElements(boilerplate);
332
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000333 // Add the constant properties to the boilerplate.
334 int length = constant_properties->length();
335 bool should_transform =
336 !is_result_from_cache && boilerplate->HasFastProperties();
337 if (should_transform || has_function_literal) {
338 // Normalize the properties of object to avoid n^2 behavior
339 // when extending the object multiple properties. Indicate the number of
340 // properties to be added.
341 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
342 }
343
344 for (int index = 0; index < length; index +=2) {
345 Handle<Object> key(constant_properties->get(index+0), isolate);
346 Handle<Object> value(constant_properties->get(index+1), isolate);
347 if (value->IsFixedArray()) {
348 // The value contains the constant_properties of a
349 // simple object or array literal.
350 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
351 value = CreateLiteralBoilerplate(isolate, literals, array);
352 if (value.is_null()) return value;
353 }
354 Handle<Object> result;
355 uint32_t element_index = 0;
356 if (key->IsSymbol()) {
357 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
358 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000359 result = SetOwnElement(boilerplate,
360 element_index,
361 value,
362 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000363 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000364 Handle<String> name(String::cast(*key));
365 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000366 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
367 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000368 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000369 } else if (key->ToArrayIndex(&element_index)) {
370 // Array index (uint32).
371 result = SetOwnElement(boilerplate,
372 element_index,
373 value,
374 kNonStrictMode);
375 } else {
376 // Non-uint32 number.
377 ASSERT(key->IsNumber());
378 double num = key->Number();
379 char arr[100];
380 Vector<char> buffer(arr, ARRAY_SIZE(arr));
381 const char* str = DoubleToCString(num, buffer);
382 Handle<String> name =
383 isolate->factory()->NewStringFromAscii(CStrVector(str));
384 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
385 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000386 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000387 // If setting the property on the boilerplate throws an
388 // exception, the exception is converted to an empty handle in
389 // the handle based operations. In that case, we need to
390 // convert back to an exception.
391 if (result.is_null()) return result;
392 }
393
394 // Transform to fast properties if necessary. For object literals with
395 // containing function literals we defer this operation until after all
396 // computed properties have been assigned so that we can generate
397 // constant function properties.
398 if (should_transform && !has_function_literal) {
399 TransformToFastProperties(boilerplate,
400 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000401 }
402
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000403 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000404}
405
406
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000407static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000408 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000409 Handle<FixedArray> literals,
410 Handle<FixedArray> elements) {
411 // Create the JSArray.
412 Handle<JSFunction> constructor(
413 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000414 Handle<Object> object = isolate->factory()->NewJSObject(constructor);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000415
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000416 const bool is_cow =
417 (elements->map() == isolate->heap()->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000418 Handle<FixedArray> copied_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000419 is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000420
421 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000422 if (is_cow) {
423#ifdef DEBUG
424 // Copy-on-write arrays must be shallow (and simple).
425 for (int i = 0; i < content->length(); i++) {
426 ASSERT(!content->get(i)->IsFixedArray());
427 }
428#endif
429 } else {
430 for (int i = 0; i < content->length(); i++) {
431 if (content->get(i)->IsFixedArray()) {
432 // The value contains the constant_properties of a
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000433 // simple object or array literal.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000434 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
435 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000436 CreateLiteralBoilerplate(isolate, literals, fa);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000437 if (result.is_null()) return result;
438 content->set(i, *result);
439 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000440 }
441 }
442
443 // Set the elements.
444 Handle<JSArray>::cast(object)->SetContent(*content);
445 return object;
446}
447
448
449static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000450 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000451 Handle<FixedArray> literals,
452 Handle<FixedArray> array) {
453 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000454 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000455 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000456 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000457 return CreateObjectLiteralBoilerplate(isolate,
458 literals,
459 elements,
460 true,
461 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000462 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000463 return CreateObjectLiteralBoilerplate(isolate,
464 literals,
465 elements,
466 false,
467 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000468 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000469 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000470 default:
471 UNREACHABLE();
472 return Handle<Object>::null();
473 }
474}
475
476
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000477RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000478 // Takes a FixedArray of elements containing the literal elements of
479 // the array literal and produces JSArray with those elements.
480 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000481 // which contains the context from which to get the Array function
482 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000483 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000484 ASSERT(args.length() == 3);
485 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000486 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000487 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000488
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000489 Handle<Object> object =
490 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000491 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000492
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000493 // Update the functions literal and return the boilerplate.
494 literals->set(literals_index, *object);
495 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000496}
497
498
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000499RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000500 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000501 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000502 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000503 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000504 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000505 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000506 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
507 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000508
509 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000510 Handle<Object> boilerplate(literals->get(literals_index), isolate);
511 if (*boilerplate == isolate->heap()->undefined_value()) {
512 boilerplate = CreateObjectLiteralBoilerplate(isolate,
513 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000514 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000515 should_have_fast_elements,
516 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000517 if (boilerplate.is_null()) return Failure::Exception();
518 // Update the functions literal and return the boilerplate.
519 literals->set(literals_index, *boilerplate);
520 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000521 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000522}
523
524
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000525RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000526 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000527 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000528 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000529 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000530 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000531 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000532 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
533 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000534
535 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000536 Handle<Object> boilerplate(literals->get(literals_index), isolate);
537 if (*boilerplate == isolate->heap()->undefined_value()) {
538 boilerplate = CreateObjectLiteralBoilerplate(isolate,
539 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000540 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000541 should_have_fast_elements,
542 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000543 if (boilerplate.is_null()) return Failure::Exception();
544 // Update the functions literal and return the boilerplate.
545 literals->set(literals_index, *boilerplate);
546 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000547 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000548}
549
550
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000551RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000552 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000553 ASSERT(args.length() == 3);
554 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000555 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000556 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
557
558 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000559 Handle<Object> boilerplate(literals->get(literals_index), isolate);
560 if (*boilerplate == isolate->heap()->undefined_value()) {
561 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000562 if (boilerplate.is_null()) return Failure::Exception();
563 // Update the functions literal and return the boilerplate.
564 literals->set(literals_index, *boilerplate);
565 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000566 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000567}
568
569
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000570RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000571 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000572 ASSERT(args.length() == 3);
573 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000574 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000575 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
576
577 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000578 Handle<Object> boilerplate(literals->get(literals_index), isolate);
579 if (*boilerplate == isolate->heap()->undefined_value()) {
580 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000581 if (boilerplate.is_null()) return Failure::Exception();
582 // Update the functions literal and return the boilerplate.
583 literals->set(literals_index, *boilerplate);
584 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000585 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000586 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000587 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000588 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000589 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000590}
591
592
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000593RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
594 ASSERT(args.length() == 2);
595 Object* handler = args[0];
596 Object* prototype = args[1];
597 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000598 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000599 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
600}
601
602
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000603RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
604 ASSERT(args.length() == 1);
605 Object* obj = args[0];
606 return obj->IsJSProxy()
607 ? isolate->heap()->true_value() : isolate->heap()->false_value();
608}
609
610
611RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
612 ASSERT(args.length() == 1);
613 CONVERT_CHECKED(JSProxy, proxy, args[0]);
614 return proxy->handler();
615}
616
617
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000618RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
619 ASSERT(args.length() == 1);
620 CONVERT_CHECKED(JSProxy, proxy, args[0]);
621 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000622 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000623}
624
625
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000626RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000627 NoHandleAllocation ha;
628 ASSERT(args.length() == 1);
629 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000630 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000631 return JSObject::cast(obj)->class_name();
632}
633
ager@chromium.org7c537e22008-10-16 08:43:32 +0000634
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000635RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
636 NoHandleAllocation ha;
637 ASSERT(args.length() == 1);
638 Object* obj = args[0];
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000639 do {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000640 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000641 } while (obj->IsJSObject() &&
642 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000643 return obj;
644}
645
646
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000647RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000648 NoHandleAllocation ha;
649 ASSERT(args.length() == 2);
650 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
651 Object* O = args[0];
652 Object* V = args[1];
653 while (true) {
654 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000655 if (prototype->IsNull()) return isolate->heap()->false_value();
656 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000657 V = prototype;
658 }
659}
660
661
ager@chromium.org9085a012009-05-11 19:22:57 +0000662// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000663RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000664 NoHandleAllocation ha;
665 ASSERT(args.length() == 2);
666 CONVERT_CHECKED(JSObject, jsobject, args[0]);
667 CONVERT_CHECKED(JSObject, proto, args[1]);
668
669 // Sanity checks. The old prototype (that we are replacing) could
670 // theoretically be null, but if it is not null then check that we
671 // didn't already install a hidden prototype here.
672 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
673 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
674 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
675
676 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000677 Object* map_or_failure;
678 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
679 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
680 return maybe_map_or_failure;
681 }
682 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000683 Map* new_proto_map = Map::cast(map_or_failure);
684
lrn@chromium.org303ada72010-10-27 09:33:13 +0000685 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
686 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
687 return maybe_map_or_failure;
688 }
689 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000690 Map* new_map = Map::cast(map_or_failure);
691
692 // Set proto's prototype to be the old prototype of the object.
693 new_proto_map->set_prototype(jsobject->GetPrototype());
694 proto->set_map(new_proto_map);
695 new_proto_map->set_is_hidden_prototype();
696
697 // Set the object's prototype to proto.
698 new_map->set_prototype(proto);
699 jsobject->set_map(new_map);
700
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000701 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000702}
703
704
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000705RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000706 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000707 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000708 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000709 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000710}
711
712
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000713// Recursively traverses hidden prototypes if property is not found
714static void GetOwnPropertyImplementation(JSObject* obj,
715 String* name,
716 LookupResult* result) {
717 obj->LocalLookupRealNamedProperty(name, result);
718
719 if (!result->IsProperty()) {
720 Object* proto = obj->GetPrototype();
721 if (proto->IsJSObject() &&
722 JSObject::cast(proto)->map()->is_hidden_prototype())
723 GetOwnPropertyImplementation(JSObject::cast(proto),
724 name, result);
725 }
726}
727
728
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000729static bool CheckAccessException(LookupResult* result,
730 v8::AccessType access_type) {
731 if (result->type() == CALLBACKS) {
732 Object* callback = result->GetCallbackObject();
733 if (callback->IsAccessorInfo()) {
734 AccessorInfo* info = AccessorInfo::cast(callback);
735 bool can_access =
736 (access_type == v8::ACCESS_HAS &&
737 (info->all_can_read() || info->all_can_write())) ||
738 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
739 (access_type == v8::ACCESS_SET && info->all_can_write());
740 return can_access;
741 }
742 }
743
744 return false;
745}
746
747
748static bool CheckAccess(JSObject* obj,
749 String* name,
750 LookupResult* result,
751 v8::AccessType access_type) {
752 ASSERT(result->IsProperty());
753
754 JSObject* holder = result->holder();
755 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000756 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000757 while (true) {
758 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000759 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000760 // Access check callback denied the access, but some properties
761 // can have a special permissions which override callbacks descision
762 // (currently see v8::AccessControl).
763 break;
764 }
765
766 if (current == holder) {
767 return true;
768 }
769
770 current = JSObject::cast(current->GetPrototype());
771 }
772
773 // API callbacks can have per callback access exceptions.
774 switch (result->type()) {
775 case CALLBACKS: {
776 if (CheckAccessException(result, access_type)) {
777 return true;
778 }
779 break;
780 }
781 case INTERCEPTOR: {
782 // If the object has an interceptor, try real named properties.
783 // Overwrite the result to fetch the correct property later.
784 holder->LookupRealNamedProperty(name, result);
785 if (result->IsProperty()) {
786 if (CheckAccessException(result, access_type)) {
787 return true;
788 }
789 }
790 break;
791 }
792 default:
793 break;
794 }
795
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000796 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000797 return false;
798}
799
800
801// TODO(1095): we should traverse hidden prototype hierachy as well.
802static bool CheckElementAccess(JSObject* obj,
803 uint32_t index,
804 v8::AccessType access_type) {
805 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000806 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000807 return false;
808 }
809
810 return true;
811}
812
813
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000814// Enumerator used as indices into the array returned from GetOwnProperty
815enum PropertyDescriptorIndices {
816 IS_ACCESSOR_INDEX,
817 VALUE_INDEX,
818 GETTER_INDEX,
819 SETTER_INDEX,
820 WRITABLE_INDEX,
821 ENUMERABLE_INDEX,
822 CONFIGURABLE_INDEX,
823 DESCRIPTOR_SIZE
824};
825
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000826// Returns an array with the property description:
827// if args[1] is not a property on args[0]
828// returns undefined
829// if args[1] is a data property on args[0]
830// [false, value, Writeable, Enumerable, Configurable]
831// if args[1] is an accessor on args[0]
832// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000833RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000834 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000835 Heap* heap = isolate->heap();
836 HandleScope scope(isolate);
837 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
838 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000839 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000840 CONVERT_ARG_CHECKED(JSObject, obj, 0);
841 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000842
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000843 // This could be an element.
844 uint32_t index;
845 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000846 switch (obj->HasLocalElement(index)) {
847 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000848 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000849
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000850 case JSObject::STRING_CHARACTER_ELEMENT: {
851 // Special handling of string objects according to ECMAScript 5
852 // 15.5.5.2. Note that this might be a string object with elements
853 // other than the actual string value. This is covered by the
854 // subsequent cases.
855 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
856 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000857 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000858
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000859 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000860 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000861 elms->set(WRITABLE_INDEX, heap->false_value());
862 elms->set(ENUMERABLE_INDEX, heap->false_value());
863 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000864 return *desc;
865 }
866
867 case JSObject::INTERCEPTED_ELEMENT:
868 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000869 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000870 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000871 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000872 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000873 elms->set(WRITABLE_INDEX, heap->true_value());
874 elms->set(ENUMERABLE_INDEX, heap->true_value());
875 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000876 return *desc;
877 }
878
879 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000880 Handle<JSObject> holder = obj;
881 if (obj->IsJSGlobalProxy()) {
882 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000883 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000884 ASSERT(proto->IsJSGlobalObject());
885 holder = Handle<JSObject>(JSObject::cast(proto));
886 }
whesse@chromium.org7b260152011-06-20 15:33:18 +0000887 FixedArray* elements = FixedArray::cast(holder->elements());
888 NumberDictionary* dictionary = NULL;
889 if (elements->map() == heap->non_strict_arguments_elements_map()) {
890 dictionary = NumberDictionary::cast(elements->get(1));
891 } else {
892 dictionary = NumberDictionary::cast(elements);
893 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000894 int entry = dictionary->FindEntry(index);
895 ASSERT(entry != NumberDictionary::kNotFound);
896 PropertyDetails details = dictionary->DetailsAt(entry);
897 switch (details.type()) {
898 case CALLBACKS: {
899 // This is an accessor property with getter and/or setter.
900 FixedArray* callbacks =
901 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000902 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000903 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
904 elms->set(GETTER_INDEX, callbacks->get(0));
905 }
906 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
907 elms->set(SETTER_INDEX, callbacks->get(1));
908 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000909 break;
910 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000911 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000912 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000913 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000914 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000915 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000916 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000917 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000918 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000919 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000920 default:
921 UNREACHABLE();
922 break;
923 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000924 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
925 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000926 return *desc;
927 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000928 }
929 }
930
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000931 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000932 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000933
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000934 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000935 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000936 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000937
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000938 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000939 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000940 }
941
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000942 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
943 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000944
945 bool is_js_accessor = (result.type() == CALLBACKS) &&
946 (result.GetCallbackObject()->IsFixedArray());
947
948 if (is_js_accessor) {
949 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000950 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000951
952 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
953 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
954 elms->set(GETTER_INDEX, structure->get(0));
955 }
956 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
957 elms->set(SETTER_INDEX, structure->get(1));
958 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000959 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000960 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
961 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000962
963 PropertyAttributes attrs;
964 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000965 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000966 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
967 if (!maybe_value->ToObject(&value)) return maybe_value;
968 }
969 elms->set(VALUE_INDEX, value);
970 }
971
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000972 return *desc;
973}
974
975
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000976RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000977 ASSERT(args.length() == 1);
978 CONVERT_CHECKED(JSObject, obj, args[0]);
979 return obj->PreventExtensions();
980}
981
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000982
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000983RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000984 ASSERT(args.length() == 1);
985 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000986 if (obj->IsJSGlobalProxy()) {
987 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000988 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000989 ASSERT(proto->IsJSGlobalObject());
990 obj = JSObject::cast(proto);
991 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000992 return obj->map()->is_extensible() ? isolate->heap()->true_value()
993 : isolate->heap()->false_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000994}
995
996
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000997RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000998 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000999 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001000 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
1001 CONVERT_ARG_CHECKED(String, pattern, 1);
1002 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001003 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1004 if (result.is_null()) return Failure::Exception();
1005 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001006}
1007
1008
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001009RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001010 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001011 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001012 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001013 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001014}
1015
1016
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001017RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001018 ASSERT(args.length() == 1);
1019 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001020 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001021 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001022}
1023
1024
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001025RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001026 ASSERT(args.length() == 2);
1027 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001028 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001029 int index = field->value();
1030 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1031 InstanceType type = templ->map()->instance_type();
1032 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1033 type == OBJECT_TEMPLATE_INFO_TYPE);
1034 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001035 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001036 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1037 } else {
1038 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1039 }
1040 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001041}
1042
1043
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001044RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001045 ASSERT(args.length() == 1);
1046 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001047 Map* old_map = object->map();
1048 bool needs_access_checks = old_map->is_access_check_needed();
1049 if (needs_access_checks) {
1050 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001051 Object* new_map;
1052 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1053 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1054 }
ager@chromium.org32912102009-01-16 10:38:43 +00001055
1056 Map::cast(new_map)->set_is_access_check_needed(false);
1057 object->set_map(Map::cast(new_map));
1058 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001059 return needs_access_checks ? isolate->heap()->true_value()
1060 : isolate->heap()->false_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001061}
1062
1063
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001064RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001065 ASSERT(args.length() == 1);
1066 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001067 Map* old_map = object->map();
1068 if (!old_map->is_access_check_needed()) {
1069 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001070 Object* new_map;
1071 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1072 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1073 }
ager@chromium.org32912102009-01-16 10:38:43 +00001074
1075 Map::cast(new_map)->set_is_access_check_needed(true);
1076 object->set_map(Map::cast(new_map));
1077 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001078 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001079}
1080
1081
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001082static Failure* ThrowRedeclarationError(Isolate* isolate,
1083 const char* type,
1084 Handle<String> name) {
1085 HandleScope scope(isolate);
1086 Handle<Object> type_handle =
1087 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001088 Handle<Object> args[2] = { type_handle, name };
1089 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001090 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1091 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001092}
1093
1094
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001095RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001096 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001097 HandleScope scope(isolate);
1098 Handle<GlobalObject> global = Handle<GlobalObject>(
1099 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001100
ager@chromium.org3811b432009-10-28 14:53:37 +00001101 Handle<Context> context = args.at<Context>(0);
1102 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001103 bool is_eval = args.smi_at(2) == 1;
1104 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(3));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001105 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001106
1107 // Compute the property attributes. According to ECMA-262, section
1108 // 13, page 71, the property must be read-only and
1109 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1110 // property as read-only, so we don't either.
1111 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1112
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001113 // Traverse the name/value pairs and set the properties.
1114 int length = pairs->length();
1115 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001116 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001117 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001118 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001119
1120 // We have to declare a global const property. To capture we only
1121 // assign to it when evaluating the assignment for "const x =
1122 // <expr>" the initial value is the hole.
1123 bool is_const_property = value->IsTheHole();
1124
1125 if (value->IsUndefined() || is_const_property) {
1126 // Lookup the property in the global object, and don't set the
1127 // value of the variable if the property is already there.
1128 LookupResult lookup;
1129 global->Lookup(*name, &lookup);
1130 if (lookup.IsProperty()) {
1131 // Determine if the property is local by comparing the holder
1132 // against the global object. The information will be used to
1133 // avoid throwing re-declaration errors when declaring
1134 // variables or constants that exist in the prototype chain.
1135 bool is_local = (*global == lookup.holder());
1136 // Get the property attributes and determine if the property is
1137 // read-only.
1138 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1139 bool is_read_only = (attributes & READ_ONLY) != 0;
1140 if (lookup.type() == INTERCEPTOR) {
1141 // If the interceptor says the property is there, we
1142 // just return undefined without overwriting the property.
1143 // Otherwise, we continue to setting the property.
1144 if (attributes != ABSENT) {
1145 // Check if the existing property conflicts with regards to const.
1146 if (is_local && (is_read_only || is_const_property)) {
1147 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001148 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001149 };
1150 // The property already exists without conflicting: Go to
1151 // the next declaration.
1152 continue;
1153 }
1154 // Fall-through and introduce the absent property by using
1155 // SetProperty.
1156 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001157 // For const properties, we treat a callback with this name
1158 // even in the prototype as a conflicting declaration.
1159 if (is_const_property && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001160 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001161 }
1162 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001163 if (is_local && (is_read_only || is_const_property)) {
1164 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001165 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001166 }
1167 // The property already exists without conflicting: Go to
1168 // the next declaration.
1169 continue;
1170 }
1171 }
1172 } else {
1173 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001174 Handle<SharedFunctionInfo> shared =
1175 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001176 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001177 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1178 context,
1179 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001180 value = function;
1181 }
1182
1183 LookupResult lookup;
1184 global->LocalLookup(*name, &lookup);
1185
1186 PropertyAttributes attributes = is_const_property
1187 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1188 : base;
1189
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001190 // There's a local property that we need to overwrite because
1191 // we're either declaring a function or there's an interceptor
1192 // that claims the property is absent.
1193 //
1194 // Check for conflicting re-declarations. We cannot have
1195 // conflicting types in case of intercepted properties because
1196 // they are absent.
1197 if (lookup.IsProperty() &&
1198 (lookup.type() != INTERCEPTOR) &&
1199 (lookup.IsReadOnly() || is_const_property)) {
1200 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001201 return ThrowRedeclarationError(isolate, type, name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001202 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001203
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001204 // Safari does not allow the invocation of callback setters for
1205 // function declarations. To mimic this behavior, we do not allow
1206 // the invocation of setters for function values. This makes a
1207 // difference for global functions with the same names as event
1208 // handlers such as "function onload() {}". Firefox does call the
1209 // onload setter in those case and Safari does not. We follow
1210 // Safari for compatibility.
1211 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001212 // Do not change DONT_DELETE to false from true.
1213 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
1214 attributes = static_cast<PropertyAttributes>(
1215 attributes | (lookup.GetAttributes() & DONT_DELETE));
1216 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001217 RETURN_IF_EMPTY_HANDLE(isolate,
1218 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001219 name,
1220 value,
1221 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001222 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001223 RETURN_IF_EMPTY_HANDLE(isolate,
1224 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001225 name,
1226 value,
1227 attributes,
1228 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001229 }
1230 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001231
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001232 ASSERT(!isolate->has_pending_exception());
1233 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001234}
1235
1236
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001237RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001238 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001239 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001240
ager@chromium.org7c537e22008-10-16 08:43:32 +00001241 CONVERT_ARG_CHECKED(Context, context, 0);
1242 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001243 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001244 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001245 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001246
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001247 // Declarations are always done in a function or global context.
1248 context = Handle<Context>(context->declaration_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001249
1250 int index;
1251 PropertyAttributes attributes;
1252 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001253 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001254 context->Lookup(name, flags, &index, &attributes);
1255
1256 if (attributes != ABSENT) {
1257 // The name was declared before; check for conflicting
1258 // re-declarations: This is similar to the code in parser.cc in
1259 // the AstBuildingParser::Declare function.
1260 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1261 // Functions are not read-only.
1262 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1263 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001264 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001265 }
1266
1267 // Initialize it if necessary.
1268 if (*initial_value != NULL) {
1269 if (index >= 0) {
1270 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001271 // the function context or the arguments object.
1272 if (holder->IsContext()) {
1273 ASSERT(holder.is_identical_to(context));
1274 if (((attributes & READ_ONLY) == 0) ||
1275 context->get(index)->IsTheHole()) {
1276 context->set(index, *initial_value);
1277 }
1278 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001279 // The holder is an arguments object.
1280 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001281 Handle<Object> result = SetElement(arguments, index, initial_value,
1282 kNonStrictMode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001283 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001284 }
1285 } else {
1286 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001287 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001288 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001289 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001290 SetProperty(context_ext, name, initial_value,
1291 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001292 }
1293 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001294
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001295 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001296 // The property is not in the function context. It needs to be
1297 // "declared" in the function context's extension context, or in the
1298 // global context.
1299 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001300 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001301 // The function context's extension context exists - use it.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001302 context_ext = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001303 } else {
1304 // The function context's extension context does not exists - allocate
1305 // it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001306 context_ext = isolate->factory()->NewJSObject(
1307 isolate->context_extension_function());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001308 // And store it in the extension slot.
1309 context->set_extension(*context_ext);
1310 }
1311 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001312
ager@chromium.org7c537e22008-10-16 08:43:32 +00001313 // Declare the property by setting it to the initial value if provided,
1314 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1315 // constant declarations).
1316 ASSERT(!context_ext->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001317 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001318 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001319 // Declaring a const context slot is a conflicting declaration if
1320 // there is a callback with that name in a prototype. It is
1321 // allowed to introduce const variables in
1322 // JSContextExtensionObjects. They are treated specially in
1323 // SetProperty and no setters are invoked for those since they are
1324 // not real JSObjects.
1325 if (initial_value->IsTheHole() &&
1326 !context_ext->IsJSContextExtensionObject()) {
1327 LookupResult lookup;
1328 context_ext->Lookup(*name, &lookup);
1329 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001330 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001331 }
1332 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001333 RETURN_IF_EMPTY_HANDLE(isolate,
1334 SetProperty(context_ext, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001335 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001336 }
1337
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001338 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001339}
1340
1341
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001342RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001343 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001344 // args[0] == name
1345 // args[1] == strict_mode
1346 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001347
1348 // Determine if we need to assign to the variable if it already
1349 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001350 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1351 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001352
1353 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001354 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001355 RUNTIME_ASSERT(args[1]->IsSmi());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001356 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001357 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001358
1359 // According to ECMA-262, section 12.2, page 62, the property must
1360 // not be deletable.
1361 PropertyAttributes attributes = DONT_DELETE;
1362
1363 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001364 // there, there is a property with this name in the prototype chain.
1365 // We follow Safari and Firefox behavior and only set the property
1366 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001367 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001368 // Note that objects can have hidden prototypes, so we need to traverse
1369 // the whole chain of hidden prototypes to do a 'local' lookup.
1370 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001371 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001372 while (true) {
1373 real_holder->LocalLookup(*name, &lookup);
1374 if (lookup.IsProperty()) {
1375 // Determine if this is a redeclaration of something read-only.
1376 if (lookup.IsReadOnly()) {
1377 // If we found readonly property on one of hidden prototypes,
1378 // just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001379 if (real_holder != isolate->context()->global()) break;
1380 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001381 }
1382
1383 // Determine if this is a redeclaration of an intercepted read-only
1384 // property and figure out if the property exists at all.
1385 bool found = true;
1386 PropertyType type = lookup.type();
1387 if (type == INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001388 HandleScope handle_scope(isolate);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001389 Handle<JSObject> holder(real_holder);
1390 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1391 real_holder = *holder;
1392 if (intercepted == ABSENT) {
1393 // The interceptor claims the property isn't there. We need to
1394 // make sure to introduce it.
1395 found = false;
1396 } else if ((intercepted & READ_ONLY) != 0) {
1397 // The property is present, but read-only. Since we're trying to
1398 // overwrite it with a variable declaration we must throw a
1399 // re-declaration error. However if we found readonly property
1400 // on one of hidden prototypes, just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001401 if (real_holder != isolate->context()->global()) break;
1402 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001403 }
1404 }
1405
1406 if (found && !assign) {
1407 // The global property is there and we're not assigning any value
1408 // to it. Just return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001409 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001410 }
1411
1412 // Assign the value (or undefined) to the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001413 Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001414 return real_holder->SetProperty(
1415 &lookup, *name, value, attributes, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001416 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001417
1418 Object* proto = real_holder->GetPrototype();
1419 if (!proto->IsJSObject())
1420 break;
1421
1422 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1423 break;
1424
1425 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001426 }
1427
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001428 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001429 if (assign) {
1430 return global->SetProperty(*name, args[2], attributes, strict_mode);
1431 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001432 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001433}
1434
1435
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001436RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001437 // All constants are declared with an initial value. The name
1438 // of the constant is the first argument and the initial value
1439 // is the second.
1440 RUNTIME_ASSERT(args.length() == 2);
1441 CONVERT_ARG_CHECKED(String, name, 0);
1442 Handle<Object> value = args.at<Object>(1);
1443
1444 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001445 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001446
1447 // According to ECMA-262, section 12.2, page 62, the property must
1448 // not be deletable. Since it's a const, it must be READ_ONLY too.
1449 PropertyAttributes attributes =
1450 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1451
1452 // Lookup the property locally in the global object. If it isn't
1453 // there, we add the property and take special precautions to always
1454 // add it as a local property even in case of callbacks in the
1455 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001456 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001457 LookupResult lookup;
1458 global->LocalLookup(*name, &lookup);
1459 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001460 return global->SetLocalPropertyIgnoreAttributes(*name,
1461 *value,
1462 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001463 }
1464
1465 // Determine if this is a redeclaration of something not
1466 // read-only. In case the result is hidden behind an interceptor we
1467 // need to ask it for the property attributes.
1468 if (!lookup.IsReadOnly()) {
1469 if (lookup.type() != INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001470 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001471 }
1472
1473 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1474
1475 // Throw re-declaration error if the intercepted property is present
1476 // but not read-only.
1477 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001478 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001479 }
1480
1481 // Restore global object from context (in case of GC) and continue
1482 // with setting the value because the property is either absent or
1483 // read-only. We also have to do redo the lookup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001484 HandleScope handle_scope(isolate);
1485 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001486
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001487 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001488 // property through an interceptor and only do it if it's
1489 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001490 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001491 RETURN_IF_EMPTY_HANDLE(isolate,
1492 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001493 name,
1494 value,
1495 attributes,
1496 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001497 return *value;
1498 }
1499
1500 // Set the value, but only we're assigning the initial value to a
1501 // constant. For now, we determine this by checking if the
1502 // current value is the hole.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001503 // Strict mode handling not needed (const disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001504 PropertyType type = lookup.type();
1505 if (type == FIELD) {
1506 FixedArray* properties = global->properties();
1507 int index = lookup.GetFieldIndex();
1508 if (properties->get(index)->IsTheHole()) {
1509 properties->set(index, *value);
1510 }
1511 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001512 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1513 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001514 }
1515 } else {
1516 // Ignore re-initialization of constants that have already been
1517 // assigned a function value.
1518 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1519 }
1520
1521 // Use the set value as the result of the operation.
1522 return *value;
1523}
1524
1525
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001526RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001527 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001528 ASSERT(args.length() == 3);
1529
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001530 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001531 ASSERT(!value->IsTheHole());
1532 CONVERT_ARG_CHECKED(Context, context, 1);
1533 Handle<String> name(String::cast(args[2]));
1534
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001535 // Initializations are always done in a function or global context.
1536 context = Handle<Context>(context->declaration_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001537
1538 int index;
1539 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001540 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001541 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001542 context->Lookup(name, flags, &index, &attributes);
1543
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001544 // In most situations, the property introduced by the const
1545 // declaration should be present in the context extension object.
1546 // However, because declaration and initialization are separate, the
1547 // property might have been deleted (if it was introduced by eval)
1548 // before we reach the initialization point.
1549 //
1550 // Example:
1551 //
1552 // function f() { eval("delete x; const x;"); }
1553 //
1554 // In that case, the initialization behaves like a normal assignment
1555 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001556 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001557 if (holder->IsContext()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001558 // Property was found in a context. Perform the assignment if we
1559 // found some non-constant or an uninitialized constant.
1560 Handle<Context> context = Handle<Context>::cast(holder);
1561 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1562 context->set(index, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001563 }
1564 } else {
1565 // The holder is an arguments object.
1566 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001567 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001568 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001569 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001570 SetElement(arguments, index, value, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001571 }
1572 return *value;
1573 }
1574
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001575 // The property could not be found, we introduce it in the global
1576 // context.
1577 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001578 Handle<JSObject> global = Handle<JSObject>(
1579 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001580 // Strict mode not needed (const disallowed in strict mode).
1581 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001582 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001583 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001584 return *value;
1585 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001586
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001587 // The property was present in a context extension object.
1588 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001589
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001590 if (*context_ext == context->extension()) {
1591 // This is the property that was introduced by the const
1592 // declaration. Set it if it hasn't been set before. NOTE: We
1593 // cannot use GetProperty() to get the current value as it
1594 // 'unholes' the value.
1595 LookupResult lookup;
1596 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1597 ASSERT(lookup.IsProperty()); // the property was declared
1598 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1599
1600 PropertyType type = lookup.type();
1601 if (type == FIELD) {
1602 FixedArray* properties = context_ext->properties();
1603 int index = lookup.GetFieldIndex();
1604 if (properties->get(index)->IsTheHole()) {
1605 properties->set(index, *value);
1606 }
1607 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001608 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1609 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001610 }
1611 } else {
1612 // We should not reach here. Any real, named property should be
1613 // either a field or a dictionary slot.
1614 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001615 }
1616 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001617 // The property was found in a different context extension object.
1618 // Set it if it is not a read-only property.
1619 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001620 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001621 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001622 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001623 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001624 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001625 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001626
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001627 return *value;
1628}
1629
1630
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001631RUNTIME_FUNCTION(MaybeObject*,
1632 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001633 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001634 ASSERT(args.length() == 2);
1635 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001636 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001637 if (object->HasFastProperties()) {
1638 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1639 }
1640 return *object;
1641}
1642
1643
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001644RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001645 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001646 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001647 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1648 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001649 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001650 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001651 CONVERT_SMI_ARG_CHECKED(index, 2);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001652 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001653 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001654 RUNTIME_ASSERT(index >= 0);
1655 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001656 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001657 Handle<Object> result = RegExpImpl::Exec(regexp,
1658 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001659 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001660 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001661 if (result.is_null()) return Failure::Exception();
1662 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001663}
1664
1665
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001666RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001667 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001668 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001669 if (elements_count > JSArray::kMaxFastElementsLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001670 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001671 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001672 Object* new_object;
1673 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001674 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001675 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1676 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001677 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001678 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1679 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001680 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1681 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001682 {
1683 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001684 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001685 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001686 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001687 }
1688 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001689 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001690 array->set_elements(elements);
1691 array->set_length(Smi::FromInt(elements_count));
1692 // Write in-object properties after the length of the array.
1693 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1694 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1695 return array;
1696}
1697
1698
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001699RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001700 AssertNoAllocation no_alloc;
1701 ASSERT(args.length() == 5);
1702 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1703 CONVERT_CHECKED(String, source, args[1]);
1704
1705 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001706 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001707
1708 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001709 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001710
1711 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001712 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001713
1714 Map* map = regexp->map();
1715 Object* constructor = map->constructor();
1716 if (constructor->IsJSFunction() &&
1717 JSFunction::cast(constructor)->initial_map() == map) {
1718 // If we still have the original map, set in-object properties directly.
1719 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1720 // TODO(lrn): Consider skipping write barrier on booleans as well.
1721 // Both true and false should be in oldspace at all times.
1722 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1723 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1724 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1725 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1726 Smi::FromInt(0),
1727 SKIP_WRITE_BARRIER);
1728 return regexp;
1729 }
1730
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001731 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001732 PropertyAttributes final =
1733 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1734 PropertyAttributes writable =
1735 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001736 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001737 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001738 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001739 source,
1740 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001741 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001742 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001743 global,
1744 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001745 ASSERT(!result->IsFailure());
1746 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001747 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001748 ignoreCase,
1749 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001750 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001751 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001752 multiline,
1753 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001754 ASSERT(!result->IsFailure());
1755 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001756 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001757 Smi::FromInt(0),
1758 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001759 ASSERT(!result->IsFailure());
1760 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001761 return regexp;
1762}
1763
1764
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001765RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001766 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001767 ASSERT(args.length() == 1);
1768 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1769 // This is necessary to enable fast checks for absence of elements
1770 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001771 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001772 return Smi::FromInt(0);
1773}
1774
1775
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001776static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1777 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001778 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001779 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001780 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1781 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1782 Handle<JSFunction> optimized =
1783 isolate->factory()->NewFunction(key,
1784 JS_OBJECT_TYPE,
1785 JSObject::kHeaderSize,
1786 code,
1787 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001788 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001789 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001790 return optimized;
1791}
1792
1793
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001794RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001795 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001796 ASSERT(args.length() == 1);
1797 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1798
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001799 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1800 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1801 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1802 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1803 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1804 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1805 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001806
1807 return *holder;
1808}
1809
1810
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001811RUNTIME_FUNCTION(MaybeObject*, Runtime_GetGlobalReceiver) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001812 // Returns a real global receiver, not one of builtins object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001813 Context* global_context =
1814 isolate->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001815 return global_context->global()->global_receiver();
1816}
1817
1818
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001819RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001820 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001821 ASSERT(args.length() == 4);
1822 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001823 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001824 Handle<String> pattern = args.at<String>(2);
1825 Handle<String> flags = args.at<String>(3);
1826
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001827 // Get the RegExp function from the context in the literals array.
1828 // This is the RegExp function from the context in which the
1829 // function was created. We do not use the RegExp function from the
1830 // current global context because this might be the RegExp function
1831 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001832 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001833 Handle<JSFunction>(
1834 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001835 // Compute the regular expression literal.
1836 bool has_pending_exception;
1837 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001838 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1839 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001840 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001841 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001842 return Failure::Exception();
1843 }
1844 literals->set(index, *regexp);
1845 return *regexp;
1846}
1847
1848
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001849RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001850 NoHandleAllocation ha;
1851 ASSERT(args.length() == 1);
1852
1853 CONVERT_CHECKED(JSFunction, f, args[0]);
1854 return f->shared()->name();
1855}
1856
1857
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001858RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001859 NoHandleAllocation ha;
1860 ASSERT(args.length() == 2);
1861
1862 CONVERT_CHECKED(JSFunction, f, args[0]);
1863 CONVERT_CHECKED(String, name, args[1]);
1864 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001865 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001866}
1867
1868
whesse@chromium.org7b260152011-06-20 15:33:18 +00001869RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetBound) {
1870 HandleScope scope(isolate);
1871 ASSERT(args.length() == 1);
1872
1873 CONVERT_CHECKED(JSFunction, fun, args[0]);
1874 fun->shared()->set_bound(true);
1875 return isolate->heap()->undefined_value();
1876}
1877
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001878RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001879 NoHandleAllocation ha;
1880 ASSERT(args.length() == 1);
1881
1882 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001883 Object* obj = f->RemovePrototype();
1884 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001885
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001886 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001887}
1888
1889
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001890RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001891 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001892 ASSERT(args.length() == 1);
1893
1894 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001895 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1896 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001897
1898 return *GetScriptWrapper(Handle<Script>::cast(script));
1899}
1900
1901
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001902RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001903 NoHandleAllocation ha;
1904 ASSERT(args.length() == 1);
1905
1906 CONVERT_CHECKED(JSFunction, f, args[0]);
1907 return f->shared()->GetSourceCode();
1908}
1909
1910
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001911RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001912 NoHandleAllocation ha;
1913 ASSERT(args.length() == 1);
1914
1915 CONVERT_CHECKED(JSFunction, fun, args[0]);
1916 int pos = fun->shared()->start_position();
1917 return Smi::FromInt(pos);
1918}
1919
1920
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001921RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001922 ASSERT(args.length() == 2);
1923
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001924 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001925 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1926
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001927 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1928
1929 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001930 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001931}
1932
1933
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001934RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001935 NoHandleAllocation ha;
1936 ASSERT(args.length() == 2);
1937
1938 CONVERT_CHECKED(JSFunction, fun, args[0]);
1939 CONVERT_CHECKED(String, name, args[1]);
1940 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001941 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001942}
1943
1944
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001945RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001946 NoHandleAllocation ha;
1947 ASSERT(args.length() == 2);
1948
1949 CONVERT_CHECKED(JSFunction, fun, args[0]);
1950 CONVERT_CHECKED(Smi, length, args[1]);
1951 fun->shared()->set_length(length->value());
1952 return length;
1953}
1954
1955
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001956RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001957 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001958 ASSERT(args.length() == 2);
1959
1960 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001961 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001962 Object* obj;
1963 { MaybeObject* maybe_obj =
1964 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1965 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1966 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001967 return args[0]; // return TOS
1968}
1969
1970
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001971RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001972 NoHandleAllocation ha;
1973 ASSERT(args.length() == 1);
1974
1975 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001976 return f->shared()->IsApiFunction() ? isolate->heap()->true_value()
1977 : isolate->heap()->false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001978}
1979
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001980
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001981RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001982 NoHandleAllocation ha;
1983 ASSERT(args.length() == 1);
1984
1985 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001986 return f->IsBuiltin() ? isolate->heap()->true_value() :
1987 isolate->heap()->false_value();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001988}
1989
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001990
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001991RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001992 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001993 ASSERT(args.length() == 2);
1994
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001995 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001996 Handle<Object> code = args.at<Object>(1);
1997
1998 Handle<Context> context(target->context());
1999
2000 if (!code->IsNull()) {
2001 RUNTIME_ASSERT(code->IsJSFunction());
2002 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002003 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002004
2005 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002006 return Failure::Exception();
2007 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002008 // Since we don't store the source for this we should never
2009 // optimize this.
2010 shared->code()->set_optimizable(false);
2011
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002012 // Set the code, scope info, formal parameter count,
2013 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002014 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002015 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002016 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002017 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002018 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002019 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002020 // Set the source code of the target function to undefined.
2021 // SetCode is only used for built-in constructors like String,
2022 // Array, and Object, and some web code
2023 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002024 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002025 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002026 // Clear the optimization hints related to the compiled code as these are no
2027 // longer valid when the code is overwritten.
2028 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002029 context = Handle<Context>(fun->context());
2030
2031 // Make sure we get a fresh copy of the literal vector to avoid
2032 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002033 int number_of_literals = fun->NumberOfLiterals();
2034 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002035 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002036 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002037 // Insert the object, regexp and array functions in the literals
2038 // array prefix. These are the functions that will be used when
2039 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002040 literals->set(JSFunction::kLiteralGlobalContextIndex,
2041 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002042 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002043 // It's okay to skip the write barrier here because the literals
2044 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002045 target->set_literals(*literals, SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002046 target->set_next_function_link(isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002047 }
2048
2049 target->set_context(*context);
2050 return *target;
2051}
2052
2053
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002054RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002055 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002056 ASSERT(args.length() == 2);
2057 CONVERT_ARG_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002058 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002059 RUNTIME_ASSERT(num >= 0);
2060 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002061 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002062}
2063
2064
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002065MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2066 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002067 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002068 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002069 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002070 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002071 }
2072 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002073 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002074}
2075
2076
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002077RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002078 NoHandleAllocation ha;
2079 ASSERT(args.length() == 2);
2080
2081 CONVERT_CHECKED(String, subject, args[0]);
2082 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002083 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002084
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002085 uint32_t i = 0;
2086 if (index->IsSmi()) {
2087 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002088 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002089 i = value;
2090 } else {
2091 ASSERT(index->IsHeapNumber());
2092 double value = HeapNumber::cast(index)->value();
2093 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002094 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002095
2096 // Flatten the string. If someone wants to get a char at an index
2097 // in a cons string, it is likely that more indices will be
2098 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002099 Object* flat;
2100 { MaybeObject* maybe_flat = subject->TryFlatten();
2101 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2102 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002103 subject = String::cast(flat);
2104
2105 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002106 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002107 }
2108
2109 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002110}
2111
2112
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002113RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002114 NoHandleAllocation ha;
2115 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002116 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002117}
2118
lrn@chromium.org25156de2010-04-06 13:10:27 +00002119
2120class FixedArrayBuilder {
2121 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002122 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2123 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002124 length_(0) {
2125 // Require a non-zero initial size. Ensures that doubling the size to
2126 // extend the array will work.
2127 ASSERT(initial_capacity > 0);
2128 }
2129
2130 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2131 : array_(backing_store),
2132 length_(0) {
2133 // Require a non-zero initial size. Ensures that doubling the size to
2134 // extend the array will work.
2135 ASSERT(backing_store->length() > 0);
2136 }
2137
2138 bool HasCapacity(int elements) {
2139 int length = array_->length();
2140 int required_length = length_ + elements;
2141 return (length >= required_length);
2142 }
2143
2144 void EnsureCapacity(int elements) {
2145 int length = array_->length();
2146 int required_length = length_ + elements;
2147 if (length < required_length) {
2148 int new_length = length;
2149 do {
2150 new_length *= 2;
2151 } while (new_length < required_length);
2152 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002153 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002154 array_->CopyTo(0, *extended_array, 0, length_);
2155 array_ = extended_array;
2156 }
2157 }
2158
2159 void Add(Object* value) {
2160 ASSERT(length_ < capacity());
2161 array_->set(length_, value);
2162 length_++;
2163 }
2164
2165 void Add(Smi* value) {
2166 ASSERT(length_ < capacity());
2167 array_->set(length_, value);
2168 length_++;
2169 }
2170
2171 Handle<FixedArray> array() {
2172 return array_;
2173 }
2174
2175 int length() {
2176 return length_;
2177 }
2178
2179 int capacity() {
2180 return array_->length();
2181 }
2182
2183 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002184 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002185 result_array->set_length(Smi::FromInt(length_));
2186 return result_array;
2187 }
2188
2189 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2190 target_array->set_elements(*array_);
2191 target_array->set_length(Smi::FromInt(length_));
2192 return target_array;
2193 }
2194
2195 private:
2196 Handle<FixedArray> array_;
2197 int length_;
2198};
2199
2200
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002201// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002202const int kStringBuilderConcatHelperLengthBits = 11;
2203const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002204
2205template <typename schar>
2206static inline void StringBuilderConcatHelper(String*,
2207 schar*,
2208 FixedArray*,
2209 int);
2210
lrn@chromium.org25156de2010-04-06 13:10:27 +00002211typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2212 StringBuilderSubstringLength;
2213typedef BitField<int,
2214 kStringBuilderConcatHelperLengthBits,
2215 kStringBuilderConcatHelperPositionBits>
2216 StringBuilderSubstringPosition;
2217
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002218
2219class ReplacementStringBuilder {
2220 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002221 ReplacementStringBuilder(Heap* heap,
2222 Handle<String> subject,
2223 int estimated_part_count)
2224 : heap_(heap),
2225 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002226 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002227 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002228 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002229 // Require a non-zero initial size. Ensures that doubling the size to
2230 // extend the array will work.
2231 ASSERT(estimated_part_count > 0);
2232 }
2233
lrn@chromium.org25156de2010-04-06 13:10:27 +00002234 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2235 int from,
2236 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002237 ASSERT(from >= 0);
2238 int length = to - from;
2239 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002240 if (StringBuilderSubstringLength::is_valid(length) &&
2241 StringBuilderSubstringPosition::is_valid(from)) {
2242 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2243 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002244 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002245 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002246 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002247 builder->Add(Smi::FromInt(-length));
2248 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002249 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002250 }
2251
2252
2253 void EnsureCapacity(int elements) {
2254 array_builder_.EnsureCapacity(elements);
2255 }
2256
2257
2258 void AddSubjectSlice(int from, int to) {
2259 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002260 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002261 }
2262
2263
2264 void AddString(Handle<String> string) {
2265 int length = string->length();
2266 ASSERT(length > 0);
2267 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002268 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002269 is_ascii_ = false;
2270 }
2271 IncrementCharacterCount(length);
2272 }
2273
2274
2275 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002276 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002277 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002278 }
2279
2280 Handle<String> joined_string;
2281 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002282 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002283 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002284 char* char_buffer = seq->GetChars();
2285 StringBuilderConcatHelper(*subject_,
2286 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002287 *array_builder_.array(),
2288 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002289 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002290 } else {
2291 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002292 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002293 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002294 uc16* char_buffer = seq->GetChars();
2295 StringBuilderConcatHelper(*subject_,
2296 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002297 *array_builder_.array(),
2298 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002299 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002300 }
2301 return joined_string;
2302 }
2303
2304
2305 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002306 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002307 V8::FatalProcessOutOfMemory("String.replace result too large.");
2308 }
2309 character_count_ += by;
2310 }
2311
lrn@chromium.org25156de2010-04-06 13:10:27 +00002312 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002313 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002314 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002315
lrn@chromium.org25156de2010-04-06 13:10:27 +00002316 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002317 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2318 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002319 }
2320
2321
ager@chromium.org04921a82011-06-27 13:21:41 +00002322 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2323 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002324 }
2325
2326
2327 void AddElement(Object* element) {
2328 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002329 ASSERT(array_builder_.capacity() > array_builder_.length());
2330 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002331 }
2332
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002333 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002334 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002335 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002336 int character_count_;
2337 bool is_ascii_;
2338};
2339
2340
2341class CompiledReplacement {
2342 public:
2343 CompiledReplacement()
2344 : parts_(1), replacement_substrings_(0) {}
2345
2346 void Compile(Handle<String> replacement,
2347 int capture_count,
2348 int subject_length);
2349
2350 void Apply(ReplacementStringBuilder* builder,
2351 int match_from,
2352 int match_to,
2353 Handle<JSArray> last_match_info);
2354
2355 // Number of distinct parts of the replacement pattern.
2356 int parts() {
2357 return parts_.length();
2358 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002359
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002360 private:
2361 enum PartType {
2362 SUBJECT_PREFIX = 1,
2363 SUBJECT_SUFFIX,
2364 SUBJECT_CAPTURE,
2365 REPLACEMENT_SUBSTRING,
2366 REPLACEMENT_STRING,
2367
2368 NUMBER_OF_PART_TYPES
2369 };
2370
2371 struct ReplacementPart {
2372 static inline ReplacementPart SubjectMatch() {
2373 return ReplacementPart(SUBJECT_CAPTURE, 0);
2374 }
2375 static inline ReplacementPart SubjectCapture(int capture_index) {
2376 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2377 }
2378 static inline ReplacementPart SubjectPrefix() {
2379 return ReplacementPart(SUBJECT_PREFIX, 0);
2380 }
2381 static inline ReplacementPart SubjectSuffix(int subject_length) {
2382 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2383 }
2384 static inline ReplacementPart ReplacementString() {
2385 return ReplacementPart(REPLACEMENT_STRING, 0);
2386 }
2387 static inline ReplacementPart ReplacementSubString(int from, int to) {
2388 ASSERT(from >= 0);
2389 ASSERT(to > from);
2390 return ReplacementPart(-from, to);
2391 }
2392
2393 // If tag <= 0 then it is the negation of a start index of a substring of
2394 // the replacement pattern, otherwise it's a value from PartType.
2395 ReplacementPart(int tag, int data)
2396 : tag(tag), data(data) {
2397 // Must be non-positive or a PartType value.
2398 ASSERT(tag < NUMBER_OF_PART_TYPES);
2399 }
2400 // Either a value of PartType or a non-positive number that is
2401 // the negation of an index into the replacement string.
2402 int tag;
2403 // The data value's interpretation depends on the value of tag:
2404 // tag == SUBJECT_PREFIX ||
2405 // tag == SUBJECT_SUFFIX: data is unused.
2406 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2407 // tag == REPLACEMENT_SUBSTRING ||
2408 // tag == REPLACEMENT_STRING: data is index into array of substrings
2409 // of the replacement string.
2410 // tag <= 0: Temporary representation of the substring of the replacement
2411 // string ranging over -tag .. data.
2412 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2413 // substring objects.
2414 int data;
2415 };
2416
2417 template<typename Char>
2418 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2419 Vector<Char> characters,
2420 int capture_count,
2421 int subject_length) {
2422 int length = characters.length();
2423 int last = 0;
2424 for (int i = 0; i < length; i++) {
2425 Char c = characters[i];
2426 if (c == '$') {
2427 int next_index = i + 1;
2428 if (next_index == length) { // No next character!
2429 break;
2430 }
2431 Char c2 = characters[next_index];
2432 switch (c2) {
2433 case '$':
2434 if (i > last) {
2435 // There is a substring before. Include the first "$".
2436 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2437 last = next_index + 1; // Continue after the second "$".
2438 } else {
2439 // Let the next substring start with the second "$".
2440 last = next_index;
2441 }
2442 i = next_index;
2443 break;
2444 case '`':
2445 if (i > last) {
2446 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2447 }
2448 parts->Add(ReplacementPart::SubjectPrefix());
2449 i = next_index;
2450 last = i + 1;
2451 break;
2452 case '\'':
2453 if (i > last) {
2454 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2455 }
2456 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2457 i = next_index;
2458 last = i + 1;
2459 break;
2460 case '&':
2461 if (i > last) {
2462 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2463 }
2464 parts->Add(ReplacementPart::SubjectMatch());
2465 i = next_index;
2466 last = i + 1;
2467 break;
2468 case '0':
2469 case '1':
2470 case '2':
2471 case '3':
2472 case '4':
2473 case '5':
2474 case '6':
2475 case '7':
2476 case '8':
2477 case '9': {
2478 int capture_ref = c2 - '0';
2479 if (capture_ref > capture_count) {
2480 i = next_index;
2481 continue;
2482 }
2483 int second_digit_index = next_index + 1;
2484 if (second_digit_index < length) {
2485 // Peek ahead to see if we have two digits.
2486 Char c3 = characters[second_digit_index];
2487 if ('0' <= c3 && c3 <= '9') { // Double digits.
2488 int double_digit_ref = capture_ref * 10 + c3 - '0';
2489 if (double_digit_ref <= capture_count) {
2490 next_index = second_digit_index;
2491 capture_ref = double_digit_ref;
2492 }
2493 }
2494 }
2495 if (capture_ref > 0) {
2496 if (i > last) {
2497 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2498 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002499 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002500 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2501 last = next_index + 1;
2502 }
2503 i = next_index;
2504 break;
2505 }
2506 default:
2507 i = next_index;
2508 break;
2509 }
2510 }
2511 }
2512 if (length > last) {
2513 if (last == 0) {
2514 parts->Add(ReplacementPart::ReplacementString());
2515 } else {
2516 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2517 }
2518 }
2519 }
2520
2521 ZoneList<ReplacementPart> parts_;
2522 ZoneList<Handle<String> > replacement_substrings_;
2523};
2524
2525
2526void CompiledReplacement::Compile(Handle<String> replacement,
2527 int capture_count,
2528 int subject_length) {
2529 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002530 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002531 AssertNoAllocation no_alloc;
2532 ParseReplacementPattern(&parts_,
2533 replacement->ToAsciiVector(),
2534 capture_count,
2535 subject_length);
2536 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002537 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002538 AssertNoAllocation no_alloc;
2539
2540 ParseReplacementPattern(&parts_,
2541 replacement->ToUC16Vector(),
2542 capture_count,
2543 subject_length);
2544 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002545 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002546 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002547 int substring_index = 0;
2548 for (int i = 0, n = parts_.length(); i < n; i++) {
2549 int tag = parts_[i].tag;
2550 if (tag <= 0) { // A replacement string slice.
2551 int from = -tag;
2552 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002553 replacement_substrings_.Add(
2554 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002555 parts_[i].tag = REPLACEMENT_SUBSTRING;
2556 parts_[i].data = substring_index;
2557 substring_index++;
2558 } else if (tag == REPLACEMENT_STRING) {
2559 replacement_substrings_.Add(replacement);
2560 parts_[i].data = substring_index;
2561 substring_index++;
2562 }
2563 }
2564}
2565
2566
2567void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2568 int match_from,
2569 int match_to,
2570 Handle<JSArray> last_match_info) {
2571 for (int i = 0, n = parts_.length(); i < n; i++) {
2572 ReplacementPart part = parts_[i];
2573 switch (part.tag) {
2574 case SUBJECT_PREFIX:
2575 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2576 break;
2577 case SUBJECT_SUFFIX: {
2578 int subject_length = part.data;
2579 if (match_to < subject_length) {
2580 builder->AddSubjectSlice(match_to, subject_length);
2581 }
2582 break;
2583 }
2584 case SUBJECT_CAPTURE: {
2585 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002586 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002587 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2588 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2589 if (from >= 0 && to > from) {
2590 builder->AddSubjectSlice(from, to);
2591 }
2592 break;
2593 }
2594 case REPLACEMENT_SUBSTRING:
2595 case REPLACEMENT_STRING:
2596 builder->AddString(replacement_substrings_[part.data]);
2597 break;
2598 default:
2599 UNREACHABLE();
2600 }
2601 }
2602}
2603
2604
2605
lrn@chromium.org303ada72010-10-27 09:33:13 +00002606MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002607 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002608 String* subject,
2609 JSRegExp* regexp,
2610 String* replacement,
2611 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002612 ASSERT(subject->IsFlat());
2613 ASSERT(replacement->IsFlat());
2614
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002615 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002616
2617 int length = subject->length();
2618 Handle<String> subject_handle(subject);
2619 Handle<JSRegExp> regexp_handle(regexp);
2620 Handle<String> replacement_handle(replacement);
2621 Handle<JSArray> last_match_info_handle(last_match_info);
2622 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2623 subject_handle,
2624 0,
2625 last_match_info_handle);
2626 if (match.is_null()) {
2627 return Failure::Exception();
2628 }
2629 if (match->IsNull()) {
2630 return *subject_handle;
2631 }
2632
2633 int capture_count = regexp_handle->CaptureCount();
2634
2635 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002636 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002637 CompiledReplacement compiled_replacement;
2638 compiled_replacement.Compile(replacement_handle,
2639 capture_count,
2640 length);
2641
2642 bool is_global = regexp_handle->GetFlags().is_global();
2643
2644 // Guessing the number of parts that the final result string is built
2645 // from. Global regexps can match any number of times, so we guess
2646 // conservatively.
2647 int expected_parts =
2648 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002649 ReplacementStringBuilder builder(isolate->heap(),
2650 subject_handle,
2651 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002652
2653 // Index of end of last match.
2654 int prev = 0;
2655
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002656 // Number of parts added by compiled replacement plus preceeding
2657 // string and possibly suffix after last match. It is possible for
2658 // all components to use two elements when encoded as two smis.
2659 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002660 bool matched = true;
2661 do {
2662 ASSERT(last_match_info_handle->HasFastElements());
2663 // Increase the capacity of the builder before entering local handle-scope,
2664 // so its internal buffer can safely allocate a new handle if it grows.
2665 builder.EnsureCapacity(parts_added_per_loop);
2666
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002667 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002668 int start, end;
2669 {
2670 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002671 FixedArray* match_info_array =
2672 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002673
2674 ASSERT_EQ(capture_count * 2 + 2,
2675 RegExpImpl::GetLastCaptureCount(match_info_array));
2676 start = RegExpImpl::GetCapture(match_info_array, 0);
2677 end = RegExpImpl::GetCapture(match_info_array, 1);
2678 }
2679
2680 if (prev < start) {
2681 builder.AddSubjectSlice(prev, start);
2682 }
2683 compiled_replacement.Apply(&builder,
2684 start,
2685 end,
2686 last_match_info_handle);
2687 prev = end;
2688
2689 // Only continue checking for global regexps.
2690 if (!is_global) break;
2691
2692 // Continue from where the match ended, unless it was an empty match.
2693 int next = end;
2694 if (start == end) {
2695 next = end + 1;
2696 if (next > length) break;
2697 }
2698
2699 match = RegExpImpl::Exec(regexp_handle,
2700 subject_handle,
2701 next,
2702 last_match_info_handle);
2703 if (match.is_null()) {
2704 return Failure::Exception();
2705 }
2706 matched = !match->IsNull();
2707 } while (matched);
2708
2709 if (prev < length) {
2710 builder.AddSubjectSlice(prev, length);
2711 }
2712
2713 return *(builder.ToString());
2714}
2715
2716
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002717template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002718MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002719 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002720 String* subject,
2721 JSRegExp* regexp,
2722 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002723 ASSERT(subject->IsFlat());
2724
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002725 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002726
2727 Handle<String> subject_handle(subject);
2728 Handle<JSRegExp> regexp_handle(regexp);
2729 Handle<JSArray> last_match_info_handle(last_match_info);
2730 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2731 subject_handle,
2732 0,
2733 last_match_info_handle);
2734 if (match.is_null()) return Failure::Exception();
2735 if (match->IsNull()) return *subject_handle;
2736
2737 ASSERT(last_match_info_handle->HasFastElements());
2738
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002739 int start, end;
2740 {
2741 AssertNoAllocation match_info_array_is_not_in_a_handle;
2742 FixedArray* match_info_array =
2743 FixedArray::cast(last_match_info_handle->elements());
2744
2745 start = RegExpImpl::GetCapture(match_info_array, 0);
2746 end = RegExpImpl::GetCapture(match_info_array, 1);
2747 }
2748
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002749 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002750 int new_length = length - (end - start);
2751 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002752 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002753 }
2754 Handle<ResultSeqString> answer;
2755 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002756 answer = Handle<ResultSeqString>::cast(
2757 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002758 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002759 answer = Handle<ResultSeqString>::cast(
2760 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002761 }
2762
2763 // If the regexp isn't global, only match once.
2764 if (!regexp_handle->GetFlags().is_global()) {
2765 if (start > 0) {
2766 String::WriteToFlat(*subject_handle,
2767 answer->GetChars(),
2768 0,
2769 start);
2770 }
2771 if (end < length) {
2772 String::WriteToFlat(*subject_handle,
2773 answer->GetChars() + start,
2774 end,
2775 length);
2776 }
2777 return *answer;
2778 }
2779
2780 int prev = 0; // Index of end of last match.
2781 int next = 0; // Start of next search (prev unless last match was empty).
2782 int position = 0;
2783
2784 do {
2785 if (prev < start) {
2786 // Add substring subject[prev;start] to answer string.
2787 String::WriteToFlat(*subject_handle,
2788 answer->GetChars() + position,
2789 prev,
2790 start);
2791 position += start - prev;
2792 }
2793 prev = end;
2794 next = end;
2795 // Continue from where the match ended, unless it was an empty match.
2796 if (start == end) {
2797 next++;
2798 if (next > length) break;
2799 }
2800 match = RegExpImpl::Exec(regexp_handle,
2801 subject_handle,
2802 next,
2803 last_match_info_handle);
2804 if (match.is_null()) return Failure::Exception();
2805 if (match->IsNull()) break;
2806
2807 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002808 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002809 {
2810 AssertNoAllocation match_info_array_is_not_in_a_handle;
2811 FixedArray* match_info_array =
2812 FixedArray::cast(last_match_info_handle->elements());
2813 start = RegExpImpl::GetCapture(match_info_array, 0);
2814 end = RegExpImpl::GetCapture(match_info_array, 1);
2815 }
2816 } while (true);
2817
2818 if (prev < length) {
2819 // Add substring subject[prev;length] to answer string.
2820 String::WriteToFlat(*subject_handle,
2821 answer->GetChars() + position,
2822 prev,
2823 length);
2824 position += length - prev;
2825 }
2826
2827 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002828 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002829 }
2830
2831 // Shorten string and fill
2832 int string_size = ResultSeqString::SizeFor(position);
2833 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2834 int delta = allocated_string_size - string_size;
2835
2836 answer->set_length(position);
2837 if (delta == 0) return *answer;
2838
2839 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002840 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002841
2842 return *answer;
2843}
2844
2845
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002846RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002847 ASSERT(args.length() == 4);
2848
2849 CONVERT_CHECKED(String, subject, args[0]);
2850 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002851 Object* flat_subject;
2852 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2853 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2854 return maybe_flat_subject;
2855 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002856 }
2857 subject = String::cast(flat_subject);
2858 }
2859
2860 CONVERT_CHECKED(String, replacement, args[2]);
2861 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002862 Object* flat_replacement;
2863 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2864 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2865 return maybe_flat_replacement;
2866 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002867 }
2868 replacement = String::cast(flat_replacement);
2869 }
2870
2871 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2872 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2873
2874 ASSERT(last_match_info->HasFastElements());
2875
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002876 if (replacement->length() == 0) {
2877 if (subject->HasOnlyAsciiChars()) {
2878 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002879 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002880 } else {
2881 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002882 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002883 }
2884 }
2885
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002886 return StringReplaceRegExpWithString(isolate,
2887 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002888 regexp,
2889 replacement,
2890 last_match_info);
2891}
2892
2893
ager@chromium.org7c537e22008-10-16 08:43:32 +00002894// Perform string match of pattern on subject, starting at start index.
2895// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002896// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002897int Runtime::StringMatch(Isolate* isolate,
2898 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00002899 Handle<String> pat,
2900 int start_index) {
2901 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002902 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002903
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002904 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002905 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002906
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002907 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002908 if (start_index + pattern_length > subject_length) return -1;
2909
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002910 if (!sub->IsFlat()) FlattenString(sub);
2911 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002912
ager@chromium.org7c537e22008-10-16 08:43:32 +00002913 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002914 // Extract flattened substrings of cons strings before determining asciiness.
2915 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002916 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002917 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002918 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002919
ager@chromium.org7c537e22008-10-16 08:43:32 +00002920 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002921 if (seq_pat->IsAsciiRepresentation()) {
2922 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2923 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002924 return SearchString(isolate,
2925 seq_sub->ToAsciiVector(),
2926 pat_vector,
2927 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002928 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002929 return SearchString(isolate,
2930 seq_sub->ToUC16Vector(),
2931 pat_vector,
2932 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002933 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002934 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2935 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002936 return SearchString(isolate,
2937 seq_sub->ToAsciiVector(),
2938 pat_vector,
2939 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002940 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002941 return SearchString(isolate,
2942 seq_sub->ToUC16Vector(),
2943 pat_vector,
2944 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002945}
2946
2947
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002948RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002949 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002950 ASSERT(args.length() == 3);
2951
ager@chromium.org7c537e22008-10-16 08:43:32 +00002952 CONVERT_ARG_CHECKED(String, sub, 0);
2953 CONVERT_ARG_CHECKED(String, pat, 1);
2954
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002955 Object* index = args[2];
2956 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002957 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002958
ager@chromium.org870a0b62008-11-04 11:43:05 +00002959 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002960 int position =
2961 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002962 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002963}
2964
2965
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002966template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002967static int StringMatchBackwards(Vector<const schar> subject,
2968 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002969 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002970 int pattern_length = pattern.length();
2971 ASSERT(pattern_length >= 1);
2972 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002973
2974 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002975 for (int i = 0; i < pattern_length; i++) {
2976 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002977 if (c > String::kMaxAsciiCharCode) {
2978 return -1;
2979 }
2980 }
2981 }
2982
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002983 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002984 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002985 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002986 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002987 while (j < pattern_length) {
2988 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002989 break;
2990 }
2991 j++;
2992 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002993 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002994 return i;
2995 }
2996 }
2997 return -1;
2998}
2999
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003000RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003001 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003002 ASSERT(args.length() == 3);
3003
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003004 CONVERT_ARG_CHECKED(String, sub, 0);
3005 CONVERT_ARG_CHECKED(String, pat, 1);
3006
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003007 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003008 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003009 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003010
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003011 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003012 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003013
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003014 if (start_index + pat_length > sub_length) {
3015 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003016 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003017
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003018 if (pat_length == 0) {
3019 return Smi::FromInt(start_index);
3020 }
3021
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003022 if (!sub->IsFlat()) FlattenString(sub);
3023 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003024
3025 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3026
3027 int position = -1;
3028
3029 if (pat->IsAsciiRepresentation()) {
3030 Vector<const char> pat_vector = pat->ToAsciiVector();
3031 if (sub->IsAsciiRepresentation()) {
3032 position = StringMatchBackwards(sub->ToAsciiVector(),
3033 pat_vector,
3034 start_index);
3035 } else {
3036 position = StringMatchBackwards(sub->ToUC16Vector(),
3037 pat_vector,
3038 start_index);
3039 }
3040 } else {
3041 Vector<const uc16> pat_vector = pat->ToUC16Vector();
3042 if (sub->IsAsciiRepresentation()) {
3043 position = StringMatchBackwards(sub->ToAsciiVector(),
3044 pat_vector,
3045 start_index);
3046 } else {
3047 position = StringMatchBackwards(sub->ToUC16Vector(),
3048 pat_vector,
3049 start_index);
3050 }
3051 }
3052
3053 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003054}
3055
3056
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003057RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003058 NoHandleAllocation ha;
3059 ASSERT(args.length() == 2);
3060
3061 CONVERT_CHECKED(String, str1, args[0]);
3062 CONVERT_CHECKED(String, str2, args[1]);
3063
3064 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003065 int str1_length = str1->length();
3066 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003067
3068 // Decide trivial cases without flattening.
3069 if (str1_length == 0) {
3070 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3071 return Smi::FromInt(-str2_length);
3072 } else {
3073 if (str2_length == 0) return Smi::FromInt(str1_length);
3074 }
3075
3076 int end = str1_length < str2_length ? str1_length : str2_length;
3077
3078 // No need to flatten if we are going to find the answer on the first
3079 // character. At this point we know there is at least one character
3080 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003081 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003082 if (d != 0) return Smi::FromInt(d);
3083
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003084 str1->TryFlatten();
3085 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003086
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003087 StringInputBuffer& buf1 =
3088 *isolate->runtime_state()->string_locale_compare_buf1();
3089 StringInputBuffer& buf2 =
3090 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003091
3092 buf1.Reset(str1);
3093 buf2.Reset(str2);
3094
3095 for (int i = 0; i < end; i++) {
3096 uint16_t char1 = buf1.GetNext();
3097 uint16_t char2 = buf2.GetNext();
3098 if (char1 != char2) return Smi::FromInt(char1 - char2);
3099 }
3100
3101 return Smi::FromInt(str1_length - str2_length);
3102}
3103
3104
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003105RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003106 NoHandleAllocation ha;
3107 ASSERT(args.length() == 3);
3108
3109 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003110 int start, end;
3111 // We have a fast integer-only case here to avoid a conversion to double in
3112 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003113 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3114 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3115 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3116 start = from_number;
3117 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003118 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003119 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3120 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003121 start = FastD2I(from_number);
3122 end = FastD2I(to_number);
3123 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003124 RUNTIME_ASSERT(end >= start);
3125 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003126 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003127 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003128 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003129}
3130
3131
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003132RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003133 ASSERT_EQ(3, args.length());
3134
3135 CONVERT_ARG_CHECKED(String, subject, 0);
3136 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3137 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3138 HandleScope handles;
3139
3140 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3141
3142 if (match.is_null()) {
3143 return Failure::Exception();
3144 }
3145 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003146 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003147 }
3148 int length = subject->length();
3149
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003150 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003151 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003152 int start;
3153 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003154 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003155 {
3156 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003157 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003158 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3159 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3160 }
3161 offsets.Add(start);
3162 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003163 if (start == end) if (++end > length) break;
3164 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003165 if (match.is_null()) {
3166 return Failure::Exception();
3167 }
3168 } while (!match->IsNull());
3169 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003170 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003171 Handle<String> substring = isolate->factory()->
3172 NewSubString(subject, offsets.at(0), offsets.at(1));
3173 elements->set(0, *substring);
3174 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003175 int from = offsets.at(i * 2);
3176 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003177 Handle<String> substring = isolate->factory()->
3178 NewProperSubString(subject, from, to);
3179 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003180 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003181 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003182 result->set_length(Smi::FromInt(matches));
3183 return *result;
3184}
3185
3186
lrn@chromium.org25156de2010-04-06 13:10:27 +00003187// Two smis before and after the match, for very long strings.
3188const int kMaxBuilderEntriesPerRegExpMatch = 5;
3189
3190
3191static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3192 Handle<JSArray> last_match_info,
3193 int match_start,
3194 int match_end) {
3195 // Fill last_match_info with a single capture.
3196 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3197 AssertNoAllocation no_gc;
3198 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3199 RegExpImpl::SetLastCaptureCount(elements, 2);
3200 RegExpImpl::SetLastInput(elements, *subject);
3201 RegExpImpl::SetLastSubject(elements, *subject);
3202 RegExpImpl::SetCapture(elements, 0, match_start);
3203 RegExpImpl::SetCapture(elements, 1, match_end);
3204}
3205
3206
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003207template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003208static bool SearchStringMultiple(Isolate* isolate,
3209 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003210 Vector<const PatternChar> pattern,
3211 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003212 FixedArrayBuilder* builder,
3213 int* match_pos) {
3214 int pos = *match_pos;
3215 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003216 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003217 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003218 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003219 while (pos <= max_search_start) {
3220 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3221 *match_pos = pos;
3222 return false;
3223 }
3224 // Position of end of previous match.
3225 int match_end = pos + pattern_length;
3226 int new_pos = search.Search(subject, match_end);
3227 if (new_pos >= 0) {
3228 // A match.
3229 if (new_pos > match_end) {
3230 ReplacementStringBuilder::AddSubjectSlice(builder,
3231 match_end,
3232 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003233 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003234 pos = new_pos;
3235 builder->Add(pattern_string);
3236 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003237 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003238 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003239 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003240
lrn@chromium.org25156de2010-04-06 13:10:27 +00003241 if (pos < max_search_start) {
3242 ReplacementStringBuilder::AddSubjectSlice(builder,
3243 pos + pattern_length,
3244 subject_length);
3245 }
3246 *match_pos = pos;
3247 return true;
3248}
3249
3250
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003251static bool SearchStringMultiple(Isolate* isolate,
3252 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003253 Handle<String> pattern,
3254 Handle<JSArray> last_match_info,
3255 FixedArrayBuilder* builder) {
3256 ASSERT(subject->IsFlat());
3257 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003258
3259 // Treating as if a previous match was before first character.
3260 int match_pos = -pattern->length();
3261
3262 for (;;) { // Break when search complete.
3263 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3264 AssertNoAllocation no_gc;
3265 if (subject->IsAsciiRepresentation()) {
3266 Vector<const char> subject_vector = subject->ToAsciiVector();
3267 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003268 if (SearchStringMultiple(isolate,
3269 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003270 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003271 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003272 builder,
3273 &match_pos)) break;
3274 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003275 if (SearchStringMultiple(isolate,
3276 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003277 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003278 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003279 builder,
3280 &match_pos)) break;
3281 }
3282 } else {
3283 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3284 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003285 if (SearchStringMultiple(isolate,
3286 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003287 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003288 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003289 builder,
3290 &match_pos)) break;
3291 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003292 if (SearchStringMultiple(isolate,
3293 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003294 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003295 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003296 builder,
3297 &match_pos)) break;
3298 }
3299 }
3300 }
3301
3302 if (match_pos >= 0) {
3303 SetLastMatchInfoNoCaptures(subject,
3304 last_match_info,
3305 match_pos,
3306 match_pos + pattern->length());
3307 return true;
3308 }
3309 return false; // No matches at all.
3310}
3311
3312
3313static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003314 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003315 Handle<String> subject,
3316 Handle<JSRegExp> regexp,
3317 Handle<JSArray> last_match_array,
3318 FixedArrayBuilder* builder) {
3319 ASSERT(subject->IsFlat());
3320 int match_start = -1;
3321 int match_end = 0;
3322 int pos = 0;
3323 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3324 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3325
3326 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003327 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003328 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003329 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003330
3331 for (;;) { // Break on failure, return on exception.
3332 RegExpImpl::IrregexpResult result =
3333 RegExpImpl::IrregexpExecOnce(regexp,
3334 subject,
3335 pos,
3336 register_vector);
3337 if (result == RegExpImpl::RE_SUCCESS) {
3338 match_start = register_vector[0];
3339 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3340 if (match_end < match_start) {
3341 ReplacementStringBuilder::AddSubjectSlice(builder,
3342 match_end,
3343 match_start);
3344 }
3345 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003346 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003347 if (!first) {
3348 builder->Add(*isolate->factory()->NewProperSubString(subject,
3349 match_start,
3350 match_end));
3351 } else {
3352 builder->Add(*isolate->factory()->NewSubString(subject,
3353 match_start,
3354 match_end));
3355 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003356 if (match_start != match_end) {
3357 pos = match_end;
3358 } else {
3359 pos = match_end + 1;
3360 if (pos > subject_length) break;
3361 }
3362 } else if (result == RegExpImpl::RE_FAILURE) {
3363 break;
3364 } else {
3365 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3366 return result;
3367 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003368 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003369 }
3370
3371 if (match_start >= 0) {
3372 if (match_end < subject_length) {
3373 ReplacementStringBuilder::AddSubjectSlice(builder,
3374 match_end,
3375 subject_length);
3376 }
3377 SetLastMatchInfoNoCaptures(subject,
3378 last_match_array,
3379 match_start,
3380 match_end);
3381 return RegExpImpl::RE_SUCCESS;
3382 } else {
3383 return RegExpImpl::RE_FAILURE; // No matches at all.
3384 }
3385}
3386
3387
3388static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003389 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003390 Handle<String> subject,
3391 Handle<JSRegExp> regexp,
3392 Handle<JSArray> last_match_array,
3393 FixedArrayBuilder* builder) {
3394
3395 ASSERT(subject->IsFlat());
3396 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3397 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3398
3399 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003400 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003401
3402 RegExpImpl::IrregexpResult result =
3403 RegExpImpl::IrregexpExecOnce(regexp,
3404 subject,
3405 0,
3406 register_vector);
3407
3408 int capture_count = regexp->CaptureCount();
3409 int subject_length = subject->length();
3410
3411 // Position to search from.
3412 int pos = 0;
3413 // End of previous match. Differs from pos if match was empty.
3414 int match_end = 0;
3415 if (result == RegExpImpl::RE_SUCCESS) {
3416 // Need to keep a copy of the previous match for creating last_match_info
3417 // at the end, so we have two vectors that we swap between.
3418 OffsetsVector registers2(required_registers);
3419 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003420 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003421 do {
3422 int match_start = register_vector[0];
3423 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3424 if (match_end < match_start) {
3425 ReplacementStringBuilder::AddSubjectSlice(builder,
3426 match_end,
3427 match_start);
3428 }
3429 match_end = register_vector[1];
3430
3431 {
3432 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003433 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003434 // Arguments array to replace function is match, captures, index and
3435 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003436 Handle<FixedArray> elements =
3437 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003438 Handle<String> match;
3439 if (!first) {
3440 match = isolate->factory()->NewProperSubString(subject,
3441 match_start,
3442 match_end);
3443 } else {
3444 match = isolate->factory()->NewSubString(subject,
3445 match_start,
3446 match_end);
3447 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003448 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003449 for (int i = 1; i <= capture_count; i++) {
3450 int start = register_vector[i * 2];
3451 if (start >= 0) {
3452 int end = register_vector[i * 2 + 1];
3453 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003454 Handle<String> substring;
3455 if (!first) {
3456 substring = isolate->factory()->NewProperSubString(subject,
3457 start,
3458 end);
3459 } else {
3460 substring = isolate->factory()->NewSubString(subject, start, end);
3461 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003462 elements->set(i, *substring);
3463 } else {
3464 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003465 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003466 }
3467 }
3468 elements->set(capture_count + 1, Smi::FromInt(match_start));
3469 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003470 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003471 }
3472 // Swap register vectors, so the last successful match is in
3473 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003474 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003475 prev_register_vector = register_vector;
3476 register_vector = tmp;
3477
3478 if (match_end > match_start) {
3479 pos = match_end;
3480 } else {
3481 pos = match_end + 1;
3482 if (pos > subject_length) {
3483 break;
3484 }
3485 }
3486
3487 result = RegExpImpl::IrregexpExecOnce(regexp,
3488 subject,
3489 pos,
3490 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003491 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003492 } while (result == RegExpImpl::RE_SUCCESS);
3493
3494 if (result != RegExpImpl::RE_EXCEPTION) {
3495 // Finished matching, with at least one match.
3496 if (match_end < subject_length) {
3497 ReplacementStringBuilder::AddSubjectSlice(builder,
3498 match_end,
3499 subject_length);
3500 }
3501
3502 int last_match_capture_count = (capture_count + 1) * 2;
3503 int last_match_array_size =
3504 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3505 last_match_array->EnsureSize(last_match_array_size);
3506 AssertNoAllocation no_gc;
3507 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3508 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3509 RegExpImpl::SetLastSubject(elements, *subject);
3510 RegExpImpl::SetLastInput(elements, *subject);
3511 for (int i = 0; i < last_match_capture_count; i++) {
3512 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3513 }
3514 return RegExpImpl::RE_SUCCESS;
3515 }
3516 }
3517 // No matches at all, return failure or exception result directly.
3518 return result;
3519}
3520
3521
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003522RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003523 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003524 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003525
3526 CONVERT_ARG_CHECKED(String, subject, 1);
3527 if (!subject->IsFlat()) { FlattenString(subject); }
3528 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3529 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3530 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3531
3532 ASSERT(last_match_info->HasFastElements());
3533 ASSERT(regexp->GetFlags().is_global());
3534 Handle<FixedArray> result_elements;
3535 if (result_array->HasFastElements()) {
3536 result_elements =
3537 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003538 }
3539 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003540 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003541 }
3542 FixedArrayBuilder builder(result_elements);
3543
3544 if (regexp->TypeTag() == JSRegExp::ATOM) {
3545 Handle<String> pattern(
3546 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003547 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003548 if (SearchStringMultiple(isolate, subject, pattern,
3549 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003550 return *builder.ToJSArray(result_array);
3551 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003552 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003553 }
3554
3555 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3556
3557 RegExpImpl::IrregexpResult result;
3558 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003559 result = SearchRegExpNoCaptureMultiple(isolate,
3560 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003561 regexp,
3562 last_match_info,
3563 &builder);
3564 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003565 result = SearchRegExpMultiple(isolate,
3566 subject,
3567 regexp,
3568 last_match_info,
3569 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003570 }
3571 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003572 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003573 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3574 return Failure::Exception();
3575}
3576
3577
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003578RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003579 NoHandleAllocation ha;
3580 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003581 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003582 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003583
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003584 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003585 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003586 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003587 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003588 // Character array used for conversion.
3589 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003590 return isolate->heap()->
3591 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003592 }
3593 }
3594
3595 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003596 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003597 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003598 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003599 }
3600 if (isinf(value)) {
3601 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003602 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003603 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003604 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003605 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003606 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003607 MaybeObject* result =
3608 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003609 DeleteArray(str);
3610 return result;
3611}
3612
3613
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003614RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003615 NoHandleAllocation ha;
3616 ASSERT(args.length() == 2);
3617
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003618 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003619 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003620 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003621 }
3622 if (isinf(value)) {
3623 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003624 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003625 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003626 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003627 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003628 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003629 int f = FastD2I(f_number);
3630 RUNTIME_ASSERT(f >= 0);
3631 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003632 MaybeObject* res =
3633 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003634 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003635 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003636}
3637
3638
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003639RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003640 NoHandleAllocation ha;
3641 ASSERT(args.length() == 2);
3642
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003643 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003644 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003645 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003646 }
3647 if (isinf(value)) {
3648 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003649 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003650 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003651 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003652 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003653 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003654 int f = FastD2I(f_number);
3655 RUNTIME_ASSERT(f >= -1 && f <= 20);
3656 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003657 MaybeObject* res =
3658 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003659 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003660 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003661}
3662
3663
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003664RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003665 NoHandleAllocation ha;
3666 ASSERT(args.length() == 2);
3667
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003668 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003669 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003670 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003671 }
3672 if (isinf(value)) {
3673 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003674 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003675 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003676 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003677 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003678 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003679 int f = FastD2I(f_number);
3680 RUNTIME_ASSERT(f >= 1 && f <= 21);
3681 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003682 MaybeObject* res =
3683 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003684 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003685 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003686}
3687
3688
3689// Returns a single character string where first character equals
3690// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003691static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003692 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003693 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003694 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003695 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003696 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003697 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003698}
3699
3700
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003701MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
3702 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003703 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003704 // Handle [] indexing on Strings
3705 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003706 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3707 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003708 }
3709
3710 // Handle [] indexing on String objects
3711 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003712 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3713 Handle<Object> result =
3714 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3715 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003716 }
3717
3718 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003719 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003720 return prototype->GetElement(index);
3721 }
3722
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003723 return GetElement(object, index);
3724}
3725
3726
lrn@chromium.org303ada72010-10-27 09:33:13 +00003727MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003728 return object->GetElement(index);
3729}
3730
3731
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003732MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
3733 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003734 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003735 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003736
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003737 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003738 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003739 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003740 isolate->factory()->NewTypeError("non_object_property_load",
3741 HandleVector(args, 2));
3742 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003743 }
3744
3745 // Check if the given key is an array index.
3746 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003747 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003748 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003749 }
3750
3751 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003752 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003753 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003754 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003755 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003756 bool has_pending_exception = false;
3757 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003758 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003759 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003760 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003761 }
3762
ager@chromium.org32912102009-01-16 10:38:43 +00003763 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003764 // the element if so.
3765 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003766 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003767 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003768 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003769 }
3770}
3771
3772
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003773RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003774 NoHandleAllocation ha;
3775 ASSERT(args.length() == 2);
3776
3777 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003778 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003779
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003780 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003781}
3782
3783
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003784// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003785RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003786 NoHandleAllocation ha;
3787 ASSERT(args.length() == 2);
3788
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003789 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003790 // itself.
3791 //
3792 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003793 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003794 // global proxy object never has properties. This is the case
3795 // because the global proxy object forwards everything to its hidden
3796 // prototype including local lookups.
3797 //
3798 // Additionally, we need to make sure that we do not cache results
3799 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003800 if (args[0]->IsJSObject() &&
3801 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003802 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003803 args[1]->IsString()) {
3804 JSObject* receiver = JSObject::cast(args[0]);
3805 String* key = String::cast(args[1]);
3806 if (receiver->HasFastProperties()) {
3807 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003808 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003809 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
3810 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003811 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003812 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003813 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003814 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003815 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003816 LookupResult result;
3817 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003818 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003819 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003820 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003821 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003822 }
3823 } else {
3824 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003825 StringDictionary* dictionary = receiver->property_dictionary();
3826 int entry = dictionary->FindEntry(key);
3827 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003828 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003829 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003830 if (!receiver->IsGlobalObject()) return value;
3831 value = JSGlobalPropertyCell::cast(value)->value();
3832 if (!value->IsTheHole()) return value;
3833 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003834 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003835 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003836 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3837 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003838 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003839 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003840 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003841 if (index >= 0 && index < str->length()) {
3842 Handle<Object> result = GetCharAt(str, index);
3843 return *result;
3844 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003845 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003846
3847 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003848 return Runtime::GetObjectProperty(isolate,
3849 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00003850 args.at<Object>(1));
3851}
3852
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003853// Implements part of 8.12.9 DefineOwnProperty.
3854// There are 3 cases that lead here:
3855// Step 4b - define a new accessor property.
3856// Steps 9c & 12 - replace an existing data property with an accessor property.
3857// Step 12 - update an existing accessor property with an accessor or generic
3858// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003859RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003860 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003861 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003862 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3863 CONVERT_CHECKED(String, name, args[1]);
3864 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003865 Object* fun = args[3];
3866 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00003867 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3868 int unchecked = flag_attr->value();
3869 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3870 RUNTIME_ASSERT(!obj->IsNull());
3871 LookupResult result;
3872 obj->LocalLookupRealNamedProperty(name, &result);
3873
3874 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3875 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3876 // delete it to avoid running into trouble in DefineAccessor, which
3877 // handles this incorrectly if the property is readonly (does nothing)
3878 if (result.IsProperty() &&
3879 (result.type() == FIELD || result.type() == NORMAL
3880 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003881 Object* ok;
3882 { MaybeObject* maybe_ok =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003883 obj->DeleteProperty(name, JSReceiver::NORMAL_DELETION);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003884 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3885 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003886 }
3887 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3888}
3889
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003890// Implements part of 8.12.9 DefineOwnProperty.
3891// There are 3 cases that lead here:
3892// Step 4a - define a new data property.
3893// Steps 9b & 12 - replace an existing accessor property with a data property.
3894// Step 12 - update an existing data property with a data or generic
3895// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003896RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003897 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003898 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003899 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3900 CONVERT_ARG_CHECKED(String, name, 1);
3901 Handle<Object> obj_value = args.at<Object>(2);
3902
3903 CONVERT_CHECKED(Smi, flag, args[3]);
3904 int unchecked = flag->value();
3905 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3906
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003907 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3908
3909 // Check if this is an element.
3910 uint32_t index;
3911 bool is_element = name->AsArrayIndex(&index);
3912
3913 // Special case for elements if any of the flags are true.
3914 // If elements are in fast case we always implicitly assume that:
3915 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3916 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3917 is_element) {
3918 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003919 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003920 // We do not need to do access checks here since these has already
3921 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003922 Handle<Object> proto(js_object->GetPrototype());
3923 // If proxy is detached, ignore the assignment. Alternatively,
3924 // we could throw an exception.
3925 if (proto->IsNull()) return *obj_value;
3926 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003927 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003928 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003929 // Make sure that we never go back to fast case.
3930 dictionary->set_requires_slow_elements();
3931 PropertyDetails details = PropertyDetails(attr, NORMAL);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003932 Handle<NumberDictionary> extended_dictionary =
3933 NumberDictionarySet(dictionary, index, obj_value, details);
3934 if (*extended_dictionary != *dictionary) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003935 if (js_object->GetElementsKind() ==
3936 JSObject::NON_STRICT_ARGUMENTS_ELEMENTS) {
3937 FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
3938 } else {
3939 js_object->set_elements(*extended_dictionary);
3940 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003941 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003942 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003943 }
3944
ager@chromium.org5c838252010-02-19 08:53:10 +00003945 LookupResult result;
whesse@chromium.org7b260152011-06-20 15:33:18 +00003946 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003947
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003948 // To be compatible with safari we do not change the value on API objects
3949 // in defineProperty. Firefox disagrees here, and actually changes the value.
3950 if (result.IsProperty() &&
3951 (result.type() == CALLBACKS) &&
3952 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003953 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003954 }
3955
ager@chromium.org5c838252010-02-19 08:53:10 +00003956 // Take special care when attributes are different and there is already
3957 // a property. For simplicity we normalize the property which enables us
3958 // to not worry about changing the instance_descriptor and creating a new
3959 // map. The current version of SetObjectProperty does not handle attributes
3960 // correctly in the case where a property is a field and is reset with
3961 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003962 if (result.IsProperty() &&
3963 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003964 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003965 if (js_object->IsJSGlobalProxy()) {
3966 // Since the result is a property, the prototype will exist so
3967 // we don't have to check for null.
3968 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003969 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003970 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003971 // Use IgnoreAttributes version since a readonly property may be
3972 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003973 return js_object->SetLocalPropertyIgnoreAttributes(*name,
3974 *obj_value,
3975 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003976 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003977
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003978 return Runtime::ForceSetObjectProperty(isolate,
3979 js_object,
3980 name,
3981 obj_value,
3982 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003983}
3984
3985
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003986// Special case for elements if any of the flags are true.
3987// If elements are in fast case we always implicitly assume that:
3988// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3989static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
3990 Handle<JSObject> js_object,
3991 uint32_t index,
3992 Handle<Object> value,
3993 PropertyAttributes attr) {
3994 // Normalize the elements to enable attributes on the property.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003995 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003996 // Make sure that we never go back to fast case.
3997 dictionary->set_requires_slow_elements();
3998 PropertyDetails details = PropertyDetails(attr, NORMAL);
3999 Handle<NumberDictionary> extended_dictionary =
4000 NumberDictionarySet(dictionary, index, value, details);
4001 if (*extended_dictionary != *dictionary) {
4002 js_object->set_elements(*extended_dictionary);
4003 }
4004 return *value;
4005}
4006
4007
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004008MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4009 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004010 Handle<Object> key,
4011 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004012 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004013 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004014 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004015
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004016 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004017 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004018 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004019 isolate->factory()->NewTypeError("non_object_property_store",
4020 HandleVector(args, 2));
4021 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004022 }
4023
4024 // If the object isn't a JavaScript object, we ignore the store.
4025 if (!object->IsJSObject()) return *value;
4026
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004027 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4028
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004029 // Check if the given key is an array index.
4030 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004031 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004032 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4033 // of a string using [] notation. We need to support this too in
4034 // JavaScript.
4035 // In the case of a String object we just need to redirect the assignment to
4036 // the underlying string if the index is in range. Since the underlying
4037 // string does nothing with the assignment then we can ignore such
4038 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004039 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004040 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004041 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004042
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004043 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4044 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
4045 }
4046
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004047 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004048 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004049 return *value;
4050 }
4051
4052 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004053 Handle<Object> result;
4054 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004055 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4056 return NormalizeObjectSetElement(isolate,
4057 js_object,
4058 index,
4059 value,
4060 attr);
4061 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004062 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004063 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004064 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004065 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004066 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004067 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004068 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004069 return *value;
4070 }
4071
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004072 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004073 bool has_pending_exception = false;
4074 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4075 if (has_pending_exception) return Failure::Exception();
4076 Handle<String> name = Handle<String>::cast(converted);
4077
4078 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004079 return js_object->SetElement(index, *value, strict_mode, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004080 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004081 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004082 }
4083}
4084
4085
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004086MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4087 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004088 Handle<Object> key,
4089 Handle<Object> value,
4090 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004091 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004092
4093 // Check if the given key is an array index.
4094 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004095 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004096 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4097 // of a string using [] notation. We need to support this too in
4098 // JavaScript.
4099 // In the case of a String object we just need to redirect the assignment to
4100 // the underlying string if the index is in range. Since the underlying
4101 // string does nothing with the assignment then we can ignore such
4102 // assignments.
4103 if (js_object->IsStringObjectWithCharacterAt(index)) {
4104 return *value;
4105 }
4106
whesse@chromium.org7b260152011-06-20 15:33:18 +00004107 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004108 }
4109
4110 if (key->IsString()) {
4111 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004112 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004113 } else {
4114 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004115 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004116 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4117 *value,
4118 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004119 }
4120 }
4121
4122 // Call-back into JavaScript to convert the key to a string.
4123 bool has_pending_exception = false;
4124 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4125 if (has_pending_exception) return Failure::Exception();
4126 Handle<String> name = Handle<String>::cast(converted);
4127
4128 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004129 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004130 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004131 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004132 }
4133}
4134
4135
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004136MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004137 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004138 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004139 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004140
4141 // Check if the given key is an array index.
4142 uint32_t index;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004143 if (receiver->IsJSObject() && key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004144 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4145 // characters of a string using [] notation. In the case of a
4146 // String object we just need to redirect the deletion to the
4147 // underlying string if the index is in range. Since the
4148 // underlying string does nothing with the deletion, we can ignore
4149 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004150 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004151 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004152 }
4153
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004154 return JSObject::cast(*receiver)->DeleteElement(
4155 index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004156 }
4157
4158 Handle<String> key_string;
4159 if (key->IsString()) {
4160 key_string = Handle<String>::cast(key);
4161 } else {
4162 // Call-back into JavaScript to convert the key to a string.
4163 bool has_pending_exception = false;
4164 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4165 if (has_pending_exception) return Failure::Exception();
4166 key_string = Handle<String>::cast(converted);
4167 }
4168
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004169 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004170 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004171}
4172
4173
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004174RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004175 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004176 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004177
4178 Handle<Object> object = args.at<Object>(0);
4179 Handle<Object> key = args.at<Object>(1);
4180 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004181 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004182 RUNTIME_ASSERT(
4183 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004184 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004185 PropertyAttributes attributes =
4186 static_cast<PropertyAttributes>(unchecked_attributes);
4187
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004188 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004189 if (args.length() == 5) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004190 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004191 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4192 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004193 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004194 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004195
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004196 return Runtime::SetObjectProperty(isolate,
4197 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004198 key,
4199 value,
4200 attributes,
4201 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004202}
4203
4204
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004205// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004206// This is used to decide if we should transform null and undefined
4207// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004208RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004209 NoHandleAllocation ha;
4210 RUNTIME_ASSERT(args.length() == 1);
4211
4212 Handle<Object> object = args.at<Object>(0);
4213
4214 if (object->IsJSFunction()) {
4215 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004216 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004217 }
4218 return isolate->heap()->undefined_value();
4219}
4220
4221
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004222// Set a local property, even if it is READ_ONLY. If the property does not
4223// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004224RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004225 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004226 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004227 CONVERT_CHECKED(JSObject, object, args[0]);
4228 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004229 // Compute attributes.
4230 PropertyAttributes attributes = NONE;
4231 if (args.length() == 4) {
4232 CONVERT_CHECKED(Smi, value_obj, args[3]);
4233 int unchecked_value = value_obj->value();
4234 // Only attribute bits should be set.
4235 RUNTIME_ASSERT(
4236 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4237 attributes = static_cast<PropertyAttributes>(unchecked_value);
4238 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004239
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004240 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004241 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004242}
4243
4244
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004245RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004246 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004247 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004248
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004249 CONVERT_CHECKED(JSReceiver, object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004250 CONVERT_CHECKED(String, key, args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004251 CONVERT_SMI_ARG_CHECKED(strict, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004252 return object->DeleteProperty(key, (strict == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004253 ? JSReceiver::STRICT_DELETION
4254 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004255}
4256
4257
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004258static Object* HasLocalPropertyImplementation(Isolate* isolate,
4259 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004260 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004261 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004262 // Handle hidden prototypes. If there's a hidden prototype above this thing
4263 // then we have to check it for properties, because they are supposed to
4264 // look like they are on this object.
4265 Handle<Object> proto(object->GetPrototype());
4266 if (proto->IsJSObject() &&
4267 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004268 return HasLocalPropertyImplementation(isolate,
4269 Handle<JSObject>::cast(proto),
4270 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004271 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004272 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004273}
4274
4275
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004276RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004277 NoHandleAllocation ha;
4278 ASSERT(args.length() == 2);
4279 CONVERT_CHECKED(String, key, args[1]);
4280
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004281 uint32_t index;
4282 const bool key_is_array_index = key->AsArrayIndex(&index);
4283
ager@chromium.org9085a012009-05-11 19:22:57 +00004284 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004285 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004286 if (obj->IsJSObject()) {
4287 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004288 // Fast case: either the key is a real named property or it is not
4289 // an array index and there are no interceptors or hidden
4290 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004291 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004292 Map* map = object->map();
4293 if (!key_is_array_index &&
4294 !map->has_named_interceptor() &&
4295 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4296 return isolate->heap()->false_value();
4297 }
4298 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004299 HandleScope scope(isolate);
4300 return HasLocalPropertyImplementation(isolate,
4301 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004302 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004303 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004304 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004305 String* string = String::cast(obj);
4306 if (index < static_cast<uint32_t>(string->length())) {
4307 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004308 }
4309 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004310 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004311}
4312
4313
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004314RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004315 NoHandleAllocation na;
4316 ASSERT(args.length() == 2);
4317
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004318 // Only JS receivers can have properties.
4319 if (args[0]->IsJSReceiver()) {
4320 JSReceiver* receiver = JSReceiver::cast(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004321 CONVERT_CHECKED(String, key, args[1]);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004322 if (receiver->HasProperty(key)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004323 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004324 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004325}
4326
4327
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004328RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004329 NoHandleAllocation na;
4330 ASSERT(args.length() == 2);
4331
4332 // Only JS objects can have elements.
4333 if (args[0]->IsJSObject()) {
4334 JSObject* object = JSObject::cast(args[0]);
4335 CONVERT_CHECKED(Smi, index_obj, args[1]);
4336 uint32_t index = index_obj->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004337 if (object->HasElement(index)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004338 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004339 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004340}
4341
4342
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004343RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004344 NoHandleAllocation ha;
4345 ASSERT(args.length() == 2);
4346
4347 CONVERT_CHECKED(JSObject, object, args[0]);
4348 CONVERT_CHECKED(String, key, args[1]);
4349
4350 uint32_t index;
4351 if (key->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004352 return isolate->heap()->ToBoolean(object->HasElement(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004353 }
4354
ager@chromium.org870a0b62008-11-04 11:43:05 +00004355 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004356 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004357}
4358
4359
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004360RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004361 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004362 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004363 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004364 return *GetKeysFor(object);
4365}
4366
4367
4368// Returns either a FixedArray as Runtime_GetPropertyNames,
4369// or, if the given object has an enum cache that contains
4370// all enumerable properties of the object and its prototypes
4371// have none, the map of the object. This is used to speed up
4372// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004373RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004374 ASSERT(args.length() == 1);
4375
4376 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4377
4378 if (raw_object->IsSimpleEnum()) return raw_object->map();
4379
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004380 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004381 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004382 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4383 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004384
4385 // Test again, since cache may have been built by preceding call.
4386 if (object->IsSimpleEnum()) return object->map();
4387
4388 return *content;
4389}
4390
4391
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004392// Find the length of the prototype chain that is to to handled as one. If a
4393// prototype object is hidden it is to be viewed as part of the the object it
4394// is prototype for.
4395static int LocalPrototypeChainLength(JSObject* obj) {
4396 int count = 1;
4397 Object* proto = obj->GetPrototype();
4398 while (proto->IsJSObject() &&
4399 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4400 count++;
4401 proto = JSObject::cast(proto)->GetPrototype();
4402 }
4403 return count;
4404}
4405
4406
4407// Return the names of the local named properties.
4408// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004409RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004410 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004411 ASSERT(args.length() == 1);
4412 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004413 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004414 }
4415 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4416
4417 // Skip the global proxy as it has no properties and always delegates to the
4418 // real global object.
4419 if (obj->IsJSGlobalProxy()) {
4420 // Only collect names if access is permitted.
4421 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004422 !isolate->MayNamedAccess(*obj,
4423 isolate->heap()->undefined_value(),
4424 v8::ACCESS_KEYS)) {
4425 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4426 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004427 }
4428 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4429 }
4430
4431 // Find the number of objects making up this.
4432 int length = LocalPrototypeChainLength(*obj);
4433
4434 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004435 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004436 int total_property_count = 0;
4437 Handle<JSObject> jsproto = obj;
4438 for (int i = 0; i < length; i++) {
4439 // Only collect names if access is permitted.
4440 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004441 !isolate->MayNamedAccess(*jsproto,
4442 isolate->heap()->undefined_value(),
4443 v8::ACCESS_KEYS)) {
4444 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4445 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004446 }
4447 int n;
4448 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4449 local_property_count[i] = n;
4450 total_property_count += n;
4451 if (i < length - 1) {
4452 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4453 }
4454 }
4455
4456 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004457 Handle<FixedArray> names =
4458 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004459
4460 // Get the property names.
4461 jsproto = obj;
4462 int proto_with_hidden_properties = 0;
4463 for (int i = 0; i < length; i++) {
4464 jsproto->GetLocalPropertyNames(*names,
4465 i == 0 ? 0 : local_property_count[i - 1]);
4466 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
4467 proto_with_hidden_properties++;
4468 }
4469 if (i < length - 1) {
4470 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4471 }
4472 }
4473
4474 // Filter out name of hidden propeties object.
4475 if (proto_with_hidden_properties > 0) {
4476 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004477 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004478 names->length() - proto_with_hidden_properties);
4479 int dest_pos = 0;
4480 for (int i = 0; i < total_property_count; i++) {
4481 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004482 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004483 continue;
4484 }
4485 names->set(dest_pos++, name);
4486 }
4487 }
4488
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004489 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004490}
4491
4492
4493// Return the names of the local indexed properties.
4494// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004495RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004496 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004497 ASSERT(args.length() == 1);
4498 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004499 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004500 }
4501 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4502
4503 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004504 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004505 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004506 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004507}
4508
4509
4510// Return information on whether an object has a named or indexed interceptor.
4511// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004512RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004513 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004514 ASSERT(args.length() == 1);
4515 if (!args[0]->IsJSObject()) {
4516 return Smi::FromInt(0);
4517 }
4518 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4519
4520 int result = 0;
4521 if (obj->HasNamedInterceptor()) result |= 2;
4522 if (obj->HasIndexedInterceptor()) result |= 1;
4523
4524 return Smi::FromInt(result);
4525}
4526
4527
4528// Return property names from named interceptor.
4529// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004530RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004531 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004532 ASSERT(args.length() == 1);
4533 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4534
4535 if (obj->HasNamedInterceptor()) {
4536 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4537 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4538 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004539 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004540}
4541
4542
4543// Return element names from indexed interceptor.
4544// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004545RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004546 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004547 ASSERT(args.length() == 1);
4548 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4549
4550 if (obj->HasIndexedInterceptor()) {
4551 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4552 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4553 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004554 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004555}
4556
4557
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004558RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004559 ASSERT_EQ(args.length(), 1);
4560 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004561 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004562 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004563
4564 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004565 // Do access checks before going to the global object.
4566 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004567 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004568 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004569 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4570 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004571 }
4572
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004573 Handle<Object> proto(object->GetPrototype());
4574 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004575 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004576 object = Handle<JSObject>::cast(proto);
4577 }
4578
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004579 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4580 LOCAL_ONLY);
4581 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4582 // property array and since the result is mutable we have to create
4583 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004584 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004585 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004586 for (int i = 0; i < length; i++) {
4587 Object* entry = contents->get(i);
4588 if (entry->IsString()) {
4589 copy->set(i, entry);
4590 } else {
4591 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004592 HandleScope scope(isolate);
4593 Handle<Object> entry_handle(entry, isolate);
4594 Handle<Object> entry_str =
4595 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004596 copy->set(i, *entry_str);
4597 }
4598 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004599 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004600}
4601
4602
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004603RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004604 NoHandleAllocation ha;
4605 ASSERT(args.length() == 1);
4606
4607 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004608 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004609 it.AdvanceToArgumentsFrame();
4610 JavaScriptFrame* frame = it.frame();
4611
4612 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004613 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004614
4615 // Try to convert the key to an index. If successful and within
4616 // index return the the argument from the frame.
4617 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004618 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004619 return frame->GetParameter(index);
4620 }
4621
4622 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004623 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004624 bool exception = false;
4625 Handle<Object> converted =
4626 Execution::ToString(args.at<Object>(0), &exception);
4627 if (exception) return Failure::Exception();
4628 Handle<String> key = Handle<String>::cast(converted);
4629
4630 // Try to convert the string key into an array index.
4631 if (key->AsArrayIndex(&index)) {
4632 if (index < n) {
4633 return frame->GetParameter(index);
4634 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004635 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004636 }
4637 }
4638
4639 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004640 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
4641 if (key->Equals(isolate->heap()->callee_symbol())) {
4642 Object* function = frame->function();
4643 if (function->IsJSFunction() &&
4644 JSFunction::cast(function)->shared()->strict_mode()) {
4645 return isolate->Throw(*isolate->factory()->NewTypeError(
4646 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
4647 }
4648 return function;
4649 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004650
4651 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004652 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004653}
4654
4655
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004656RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004657 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004658
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004659 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004660 Handle<Object> object = args.at<Object>(0);
4661 if (object->IsJSObject()) {
4662 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004663 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004664 MaybeObject* ok = js_object->TransformToFastProperties(0);
4665 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004666 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004667 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004668 return *object;
4669}
4670
4671
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004672RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004673 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004674
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004675 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004676 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004677 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004678 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004679 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004680 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004681 return *object;
4682}
4683
4684
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004685RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004686 NoHandleAllocation ha;
4687 ASSERT(args.length() == 1);
4688
4689 return args[0]->ToBoolean();
4690}
4691
4692
4693// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4694// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004695RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004696 NoHandleAllocation ha;
4697
4698 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004699 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004700 HeapObject* heap_obj = HeapObject::cast(obj);
4701
4702 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004703 if (heap_obj->map()->is_undetectable()) {
4704 return isolate->heap()->undefined_symbol();
4705 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004706
4707 InstanceType instance_type = heap_obj->map()->instance_type();
4708 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004709 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004710 }
4711
4712 switch (instance_type) {
4713 case ODDBALL_TYPE:
4714 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004715 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004716 }
4717 if (heap_obj->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004718 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004719 }
4720 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004721 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004722 case JS_FUNCTION_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004723 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004724 default:
4725 // For any kind of object not handled above, the spec rule for
4726 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004727 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004728 }
4729}
4730
4731
lrn@chromium.org25156de2010-04-06 13:10:27 +00004732static bool AreDigits(const char*s, int from, int to) {
4733 for (int i = from; i < to; i++) {
4734 if (s[i] < '0' || s[i] > '9') return false;
4735 }
4736
4737 return true;
4738}
4739
4740
4741static int ParseDecimalInteger(const char*s, int from, int to) {
4742 ASSERT(to - from < 10); // Overflow is not possible.
4743 ASSERT(from < to);
4744 int d = s[from] - '0';
4745
4746 for (int i = from + 1; i < to; i++) {
4747 d = 10 * d + (s[i] - '0');
4748 }
4749
4750 return d;
4751}
4752
4753
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004754RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004755 NoHandleAllocation ha;
4756 ASSERT(args.length() == 1);
4757 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004758 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004759
4760 // Fast case: short integer or some sorts of junk values.
4761 int len = subject->length();
4762 if (subject->IsSeqAsciiString()) {
4763 if (len == 0) return Smi::FromInt(0);
4764
4765 char const* data = SeqAsciiString::cast(subject)->GetChars();
4766 bool minus = (data[0] == '-');
4767 int start_pos = (minus ? 1 : 0);
4768
4769 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004770 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004771 } else if (data[start_pos] > '9') {
4772 // Fast check for a junk value. A valid string may start from a
4773 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4774 // the 'I' character ('Infinity'). All of that have codes not greater than
4775 // '9' except 'I'.
4776 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004777 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004778 }
4779 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4780 // The maximal/minimal smi has 10 digits. If the string has less digits we
4781 // know it will fit into the smi-data type.
4782 int d = ParseDecimalInteger(data, start_pos, len);
4783 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004784 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004785 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004786 } else if (!subject->HasHashCode() &&
4787 len <= String::kMaxArrayIndexSize &&
4788 (len == 1 || data[0] != '0')) {
4789 // String hash is not calculated yet but all the data are present.
4790 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004791 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004792#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004793 subject->Hash(); // Force hash calculation.
4794 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4795 static_cast<int>(hash));
4796#endif
4797 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004798 }
4799 return Smi::FromInt(d);
4800 }
4801 }
4802
4803 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004804 return isolate->heap()->NumberFromDouble(
4805 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004806}
4807
4808
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004809RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004810 NoHandleAllocation ha;
4811 ASSERT(args.length() == 1);
4812
4813 CONVERT_CHECKED(JSArray, codes, args[0]);
4814 int length = Smi::cast(codes->length())->value();
4815
4816 // Check if the string can be ASCII.
4817 int i;
4818 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004819 Object* element;
4820 { MaybeObject* maybe_element = codes->GetElement(i);
4821 // We probably can't get an exception here, but just in order to enforce
4822 // the checking of inputs in the runtime calls we check here.
4823 if (!maybe_element->ToObject(&element)) return maybe_element;
4824 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004825 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4826 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4827 break;
4828 }
4829
lrn@chromium.org303ada72010-10-27 09:33:13 +00004830 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004831 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004832 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004833 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004834 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004835 }
4836
lrn@chromium.org303ada72010-10-27 09:33:13 +00004837 Object* object = NULL;
4838 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004839 String* result = String::cast(object);
4840 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004841 Object* element;
4842 { MaybeObject* maybe_element = codes->GetElement(i);
4843 if (!maybe_element->ToObject(&element)) return maybe_element;
4844 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004845 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004846 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004847 }
4848 return result;
4849}
4850
4851
4852// kNotEscaped is generated by the following:
4853//
4854// #!/bin/perl
4855// for (my $i = 0; $i < 256; $i++) {
4856// print "\n" if $i % 16 == 0;
4857// my $c = chr($i);
4858// my $escaped = 1;
4859// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4860// print $escaped ? "0, " : "1, ";
4861// }
4862
4863
4864static bool IsNotEscaped(uint16_t character) {
4865 // Only for 8 bit characters, the rest are always escaped (in a different way)
4866 ASSERT(character < 256);
4867 static const char kNotEscaped[256] = {
4868 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4869 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4870 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4871 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4872 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4873 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4874 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4875 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4876 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4877 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4878 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4879 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4880 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4881 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4882 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4883 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4884 };
4885 return kNotEscaped[character] != 0;
4886}
4887
4888
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004889RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004890 const char hex_chars[] = "0123456789ABCDEF";
4891 NoHandleAllocation ha;
4892 ASSERT(args.length() == 1);
4893 CONVERT_CHECKED(String, source, args[0]);
4894
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004895 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004896
4897 int escaped_length = 0;
4898 int length = source->length();
4899 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004900 Access<StringInputBuffer> buffer(
4901 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004902 buffer->Reset(source);
4903 while (buffer->has_more()) {
4904 uint16_t character = buffer->GetNext();
4905 if (character >= 256) {
4906 escaped_length += 6;
4907 } else if (IsNotEscaped(character)) {
4908 escaped_length++;
4909 } else {
4910 escaped_length += 3;
4911 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004912 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004913 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004914 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004915 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004916 return Failure::OutOfMemoryException();
4917 }
4918 }
4919 }
4920 // No length change implies no change. Return original string if no change.
4921 if (escaped_length == length) {
4922 return source;
4923 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004924 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004925 { MaybeObject* maybe_o =
4926 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004927 if (!maybe_o->ToObject(&o)) return maybe_o;
4928 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004929 String* destination = String::cast(o);
4930 int dest_position = 0;
4931
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004932 Access<StringInputBuffer> buffer(
4933 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004934 buffer->Rewind();
4935 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004936 uint16_t chr = buffer->GetNext();
4937 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004938 destination->Set(dest_position, '%');
4939 destination->Set(dest_position+1, 'u');
4940 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4941 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4942 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4943 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004944 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004945 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004946 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004947 dest_position++;
4948 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004949 destination->Set(dest_position, '%');
4950 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4951 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004952 dest_position += 3;
4953 }
4954 }
4955 return destination;
4956}
4957
4958
4959static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4960 static const signed char kHexValue['g'] = {
4961 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4962 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4963 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4964 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4965 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4966 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4967 -1, 10, 11, 12, 13, 14, 15 };
4968
4969 if (character1 > 'f') return -1;
4970 int hi = kHexValue[character1];
4971 if (hi == -1) return -1;
4972 if (character2 > 'f') return -1;
4973 int lo = kHexValue[character2];
4974 if (lo == -1) return -1;
4975 return (hi << 4) + lo;
4976}
4977
4978
ager@chromium.org870a0b62008-11-04 11:43:05 +00004979static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004980 int i,
4981 int length,
4982 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004983 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004984 int32_t hi = 0;
4985 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004986 if (character == '%' &&
4987 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004988 source->Get(i + 1) == 'u' &&
4989 (hi = TwoDigitHex(source->Get(i + 2),
4990 source->Get(i + 3))) != -1 &&
4991 (lo = TwoDigitHex(source->Get(i + 4),
4992 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004993 *step = 6;
4994 return (hi << 8) + lo;
4995 } else if (character == '%' &&
4996 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004997 (lo = TwoDigitHex(source->Get(i + 1),
4998 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004999 *step = 3;
5000 return lo;
5001 } else {
5002 *step = 1;
5003 return character;
5004 }
5005}
5006
5007
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005008RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005009 NoHandleAllocation ha;
5010 ASSERT(args.length() == 1);
5011 CONVERT_CHECKED(String, source, args[0]);
5012
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005013 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005014
5015 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005016 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005017
5018 int unescaped_length = 0;
5019 for (int i = 0; i < length; unescaped_length++) {
5020 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005021 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005022 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005023 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005024 i += step;
5025 }
5026
5027 // No length change implies no change. Return original string if no change.
5028 if (unescaped_length == length)
5029 return source;
5030
lrn@chromium.org303ada72010-10-27 09:33:13 +00005031 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005032 { MaybeObject* maybe_o =
5033 ascii ?
5034 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5035 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005036 if (!maybe_o->ToObject(&o)) return maybe_o;
5037 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005038 String* destination = String::cast(o);
5039
5040 int dest_position = 0;
5041 for (int i = 0; i < length; dest_position++) {
5042 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005043 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005044 i += step;
5045 }
5046 return destination;
5047}
5048
5049
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005050static const unsigned int kQuoteTableLength = 128u;
5051
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005052static const int kJsonQuotesCharactersPerEntry = 8;
5053static const char* const JsonQuotes =
5054 "\\u0000 \\u0001 \\u0002 \\u0003 "
5055 "\\u0004 \\u0005 \\u0006 \\u0007 "
5056 "\\b \\t \\n \\u000b "
5057 "\\f \\r \\u000e \\u000f "
5058 "\\u0010 \\u0011 \\u0012 \\u0013 "
5059 "\\u0014 \\u0015 \\u0016 \\u0017 "
5060 "\\u0018 \\u0019 \\u001a \\u001b "
5061 "\\u001c \\u001d \\u001e \\u001f "
5062 " ! \\\" # "
5063 "$ % & ' "
5064 "( ) * + "
5065 ", - . / "
5066 "0 1 2 3 "
5067 "4 5 6 7 "
5068 "8 9 : ; "
5069 "< = > ? "
5070 "@ A B C "
5071 "D E F G "
5072 "H I J K "
5073 "L M N O "
5074 "P Q R S "
5075 "T U V W "
5076 "X Y Z [ "
5077 "\\\\ ] ^ _ "
5078 "` a b c "
5079 "d e f g "
5080 "h i j k "
5081 "l m n o "
5082 "p q r s "
5083 "t u v w "
5084 "x y z { "
5085 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005086
5087
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005088// For a string that is less than 32k characters it should always be
5089// possible to allocate it in new space.
5090static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5091
5092
5093// Doing JSON quoting cannot make the string more than this many times larger.
5094static const int kJsonQuoteWorstCaseBlowup = 6;
5095
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005096static const int kSpaceForQuotesAndComma = 3;
5097static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005098
5099// Covers the entire ASCII range (all other characters are unchanged by JSON
5100// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005101static const byte JsonQuoteLengths[kQuoteTableLength] = {
5102 6, 6, 6, 6, 6, 6, 6, 6,
5103 2, 2, 2, 6, 2, 2, 6, 6,
5104 6, 6, 6, 6, 6, 6, 6, 6,
5105 6, 6, 6, 6, 6, 6, 6, 6,
5106 1, 1, 2, 1, 1, 1, 1, 1,
5107 1, 1, 1, 1, 1, 1, 1, 1,
5108 1, 1, 1, 1, 1, 1, 1, 1,
5109 1, 1, 1, 1, 1, 1, 1, 1,
5110 1, 1, 1, 1, 1, 1, 1, 1,
5111 1, 1, 1, 1, 1, 1, 1, 1,
5112 1, 1, 1, 1, 1, 1, 1, 1,
5113 1, 1, 1, 1, 2, 1, 1, 1,
5114 1, 1, 1, 1, 1, 1, 1, 1,
5115 1, 1, 1, 1, 1, 1, 1, 1,
5116 1, 1, 1, 1, 1, 1, 1, 1,
5117 1, 1, 1, 1, 1, 1, 1, 1,
5118};
5119
5120
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005121template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005122MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005123
5124
5125template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005126MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5127 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005128}
5129
5130
5131template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005132MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5133 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005134}
5135
5136
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005137template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005138static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5139 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005140 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005141 const Char* read_cursor = characters.start();
5142 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005143 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005144 int quoted_length = kSpaceForQuotes;
5145 while (read_cursor < end) {
5146 Char c = *(read_cursor++);
5147 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5148 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005149 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005150 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005151 }
5152 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005153 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5154 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005155 Object* new_object;
5156 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005157 return new_alloc;
5158 }
5159 StringType* new_string = StringType::cast(new_object);
5160
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005161 Char* write_cursor = reinterpret_cast<Char*>(
5162 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005163 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005164 *(write_cursor++) = '"';
5165
5166 read_cursor = characters.start();
5167 while (read_cursor < end) {
5168 Char c = *(read_cursor++);
5169 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5170 *(write_cursor++) = c;
5171 } else {
5172 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5173 const char* replacement = JsonQuotes +
5174 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5175 for (int i = 0; i < len; i++) {
5176 *write_cursor++ = *replacement++;
5177 }
5178 }
5179 }
5180 *(write_cursor++) = '"';
5181 return new_string;
5182}
5183
5184
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005185template <typename SinkChar, typename SourceChar>
5186static inline SinkChar* WriteQuoteJsonString(
5187 Isolate* isolate,
5188 SinkChar* write_cursor,
5189 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005190 // SinkChar is only char if SourceChar is guaranteed to be char.
5191 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005192 const SourceChar* read_cursor = characters.start();
5193 const SourceChar* end = read_cursor + characters.length();
5194 *(write_cursor++) = '"';
5195 while (read_cursor < end) {
5196 SourceChar c = *(read_cursor++);
5197 if (sizeof(SourceChar) > 1u &&
5198 static_cast<unsigned>(c) >= kQuoteTableLength) {
5199 *(write_cursor++) = static_cast<SinkChar>(c);
5200 } else {
5201 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5202 const char* replacement = JsonQuotes +
5203 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5204 write_cursor[0] = replacement[0];
5205 if (len > 1) {
5206 write_cursor[1] = replacement[1];
5207 if (len > 2) {
5208 ASSERT(len == 6);
5209 write_cursor[2] = replacement[2];
5210 write_cursor[3] = replacement[3];
5211 write_cursor[4] = replacement[4];
5212 write_cursor[5] = replacement[5];
5213 }
5214 }
5215 write_cursor += len;
5216 }
5217 }
5218 *(write_cursor++) = '"';
5219 return write_cursor;
5220}
5221
5222
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005223template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005224static MaybeObject* QuoteJsonString(Isolate* isolate,
5225 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005226 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005227 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005228 int worst_case_length =
5229 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005230 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005231 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005232 }
5233
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005234 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5235 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005236 Object* new_object;
5237 if (!new_alloc->ToObject(&new_object)) {
5238 return new_alloc;
5239 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005240 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005241 // Even if our string is small enough to fit in new space we still have to
5242 // handle it being allocated in old space as may happen in the third
5243 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5244 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005245 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005246 }
5247 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005248 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005249
5250 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5251 Char* write_cursor = reinterpret_cast<Char*>(
5252 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005253 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005254 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5255 write_cursor,
5256 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005257 int final_length = static_cast<int>(
5258 write_cursor - reinterpret_cast<Char*>(
5259 new_string->address() + SeqAsciiString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005260 isolate->heap()->new_space()->
5261 template ShrinkStringAtAllocationBoundary<StringType>(
5262 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005263 return new_string;
5264}
5265
5266
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005267RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005268 NoHandleAllocation ha;
5269 CONVERT_CHECKED(String, str, args[0]);
5270 if (!str->IsFlat()) {
5271 MaybeObject* try_flatten = str->TryFlatten();
5272 Object* flat;
5273 if (!try_flatten->ToObject(&flat)) {
5274 return try_flatten;
5275 }
5276 str = String::cast(flat);
5277 ASSERT(str->IsFlat());
5278 }
5279 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005280 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
5281 str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005282 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005283 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
5284 str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005285 }
5286}
5287
5288
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005289RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005290 NoHandleAllocation ha;
5291 CONVERT_CHECKED(String, str, args[0]);
5292 if (!str->IsFlat()) {
5293 MaybeObject* try_flatten = str->TryFlatten();
5294 Object* flat;
5295 if (!try_flatten->ToObject(&flat)) {
5296 return try_flatten;
5297 }
5298 str = String::cast(flat);
5299 ASSERT(str->IsFlat());
5300 }
5301 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005302 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
5303 str->ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005304 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005305 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
5306 str->ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005307 }
5308}
5309
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005310
5311template <typename Char, typename StringType>
5312static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5313 FixedArray* array,
5314 int worst_case_length) {
5315 int length = array->length();
5316
5317 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5318 worst_case_length);
5319 Object* new_object;
5320 if (!new_alloc->ToObject(&new_object)) {
5321 return new_alloc;
5322 }
5323 if (!isolate->heap()->new_space()->Contains(new_object)) {
5324 // Even if our string is small enough to fit in new space we still have to
5325 // handle it being allocated in old space as may happen in the third
5326 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5327 // CEntryStub::GenerateCore.
5328 return isolate->heap()->undefined_value();
5329 }
5330 AssertNoAllocation no_gc;
5331 StringType* new_string = StringType::cast(new_object);
5332 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5333
5334 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5335 Char* write_cursor = reinterpret_cast<Char*>(
5336 new_string->address() + SeqAsciiString::kHeaderSize);
5337 *(write_cursor++) = '[';
5338 for (int i = 0; i < length; i++) {
5339 if (i != 0) *(write_cursor++) = ',';
5340 String* str = String::cast(array->get(i));
5341 if (str->IsTwoByteRepresentation()) {
5342 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5343 write_cursor,
5344 str->ToUC16Vector());
5345 } else {
5346 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5347 write_cursor,
5348 str->ToAsciiVector());
5349 }
5350 }
5351 *(write_cursor++) = ']';
5352
5353 int final_length = static_cast<int>(
5354 write_cursor - reinterpret_cast<Char*>(
5355 new_string->address() + SeqAsciiString::kHeaderSize));
5356 isolate->heap()->new_space()->
5357 template ShrinkStringAtAllocationBoundary<StringType>(
5358 new_string, final_length);
5359 return new_string;
5360}
5361
5362
5363RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5364 NoHandleAllocation ha;
5365 ASSERT(args.length() == 1);
5366 CONVERT_CHECKED(JSArray, array, args[0]);
5367
5368 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5369 FixedArray* elements = FixedArray::cast(array->elements());
5370 int n = elements->length();
5371 bool ascii = true;
5372 int total_length = 0;
5373
5374 for (int i = 0; i < n; i++) {
5375 Object* elt = elements->get(i);
5376 if (!elt->IsString()) return isolate->heap()->undefined_value();
5377 String* element = String::cast(elt);
5378 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5379 total_length += element->length();
5380 if (ascii && element->IsTwoByteRepresentation()) {
5381 ascii = false;
5382 }
5383 }
5384
5385 int worst_case_length =
5386 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5387 + total_length * kJsonQuoteWorstCaseBlowup;
5388
5389 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5390 return isolate->heap()->undefined_value();
5391 }
5392
5393 if (ascii) {
5394 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5395 elements,
5396 worst_case_length);
5397 } else {
5398 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5399 elements,
5400 worst_case_length);
5401 }
5402}
5403
5404
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005405RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005406 NoHandleAllocation ha;
5407
5408 CONVERT_CHECKED(String, s, args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005409 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005410
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005411 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005412
lrn@chromium.org25156de2010-04-06 13:10:27 +00005413 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005414 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005415 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005416}
5417
5418
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005419RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005420 NoHandleAllocation ha;
5421 CONVERT_CHECKED(String, str, args[0]);
5422
5423 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005424 double value = StringToDouble(isolate->unicode_cache(),
5425 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005426
5427 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005428 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005429}
5430
5431
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005432template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005433MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005434 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005435 String* s,
5436 int length,
5437 int input_string_length,
5438 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005439 // We try this twice, once with the assumption that the result is no longer
5440 // than the input and, if that assumption breaks, again with the exact
5441 // length. This may not be pretty, but it is nicer than what was here before
5442 // and I hereby claim my vaffel-is.
5443 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005444 // Allocate the resulting string.
5445 //
5446 // NOTE: This assumes that the upper/lower case of an ascii
5447 // character is also ascii. This is currently the case, but it
5448 // might break in the future if we implement more context and locale
5449 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005450 Object* o;
5451 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005452 ? isolate->heap()->AllocateRawAsciiString(length)
5453 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005454 if (!maybe_o->ToObject(&o)) return maybe_o;
5455 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005456 String* result = String::cast(o);
5457 bool has_changed_character = false;
5458
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005459 // Convert all characters to upper case, assuming that they will fit
5460 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005461 Access<StringInputBuffer> buffer(
5462 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005463 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005464 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005465 // We can assume that the string is not empty
5466 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005467 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005468 bool has_next = buffer->has_more();
5469 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005470 int char_length = mapping->get(current, next, chars);
5471 if (char_length == 0) {
5472 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005473 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005474 i++;
5475 } else if (char_length == 1) {
5476 // Common case: converting the letter resulted in one character.
5477 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005478 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005479 has_changed_character = true;
5480 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005481 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005482 // We've assumed that the result would be as long as the
5483 // input but here is a character that converts to several
5484 // characters. No matter, we calculate the exact length
5485 // of the result and try the whole thing again.
5486 //
5487 // Note that this leaves room for optimization. We could just
5488 // memcpy what we already have to the result string. Also,
5489 // the result string is the last object allocated we could
5490 // "realloc" it and probably, in the vast majority of cases,
5491 // extend the existing string to be able to hold the full
5492 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005493 int next_length = 0;
5494 if (has_next) {
5495 next_length = mapping->get(next, 0, chars);
5496 if (next_length == 0) next_length = 1;
5497 }
5498 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005499 while (buffer->has_more()) {
5500 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005501 // NOTE: we use 0 as the next character here because, while
5502 // the next character may affect what a character converts to,
5503 // it does not in any case affect the length of what it convert
5504 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005505 int char_length = mapping->get(current, 0, chars);
5506 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005507 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005508 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005509 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005510 return Failure::OutOfMemoryException();
5511 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005512 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005513 // Try again with the real length.
5514 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005515 } else {
5516 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005517 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005518 i++;
5519 }
5520 has_changed_character = true;
5521 }
5522 current = next;
5523 }
5524 if (has_changed_character) {
5525 return result;
5526 } else {
5527 // If we didn't actually change anything in doing the conversion
5528 // we simple return the result and let the converted string
5529 // become garbage; there is no reason to keep two identical strings
5530 // alive.
5531 return s;
5532 }
5533}
5534
5535
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005536namespace {
5537
lrn@chromium.org303ada72010-10-27 09:33:13 +00005538static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5539
5540
5541// Given a word and two range boundaries returns a word with high bit
5542// set in every byte iff the corresponding input byte was strictly in
5543// the range (m, n). All the other bits in the result are cleared.
5544// This function is only useful when it can be inlined and the
5545// boundaries are statically known.
5546// Requires: all bytes in the input word and the boundaries must be
5547// ascii (less than 0x7F).
5548static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5549 // Every byte in an ascii string is less than or equal to 0x7F.
5550 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5551 // Use strict inequalities since in edge cases the function could be
5552 // further simplified.
5553 ASSERT(0 < m && m < n && n < 0x7F);
5554 // Has high bit set in every w byte less than n.
5555 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5556 // Has high bit set in every w byte greater than m.
5557 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5558 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5559}
5560
5561
5562enum AsciiCaseConversion {
5563 ASCII_TO_LOWER,
5564 ASCII_TO_UPPER
5565};
5566
5567
5568template <AsciiCaseConversion dir>
5569struct FastAsciiConverter {
5570 static bool Convert(char* dst, char* src, int length) {
5571#ifdef DEBUG
5572 char* saved_dst = dst;
5573 char* saved_src = src;
5574#endif
5575 // We rely on the distance between upper and lower case letters
5576 // being a known power of 2.
5577 ASSERT('a' - 'A' == (1 << 5));
5578 // Boundaries for the range of input characters than require conversion.
5579 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5580 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5581 bool changed = false;
5582 char* const limit = src + length;
5583#ifdef V8_HOST_CAN_READ_UNALIGNED
5584 // Process the prefix of the input that requires no conversion one
5585 // (machine) word at a time.
5586 while (src <= limit - sizeof(uintptr_t)) {
5587 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5588 if (AsciiRangeMask(w, lo, hi) != 0) {
5589 changed = true;
5590 break;
5591 }
5592 *reinterpret_cast<uintptr_t*>(dst) = w;
5593 src += sizeof(uintptr_t);
5594 dst += sizeof(uintptr_t);
5595 }
5596 // Process the remainder of the input performing conversion when
5597 // required one word at a time.
5598 while (src <= limit - sizeof(uintptr_t)) {
5599 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5600 uintptr_t m = AsciiRangeMask(w, lo, hi);
5601 // The mask has high (7th) bit set in every byte that needs
5602 // conversion and we know that the distance between cases is
5603 // 1 << 5.
5604 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5605 src += sizeof(uintptr_t);
5606 dst += sizeof(uintptr_t);
5607 }
5608#endif
5609 // Process the last few bytes of the input (or the whole input if
5610 // unaligned access is not supported).
5611 while (src < limit) {
5612 char c = *src;
5613 if (lo < c && c < hi) {
5614 c ^= (1 << 5);
5615 changed = true;
5616 }
5617 *dst = c;
5618 ++src;
5619 ++dst;
5620 }
5621#ifdef DEBUG
5622 CheckConvert(saved_dst, saved_src, length, changed);
5623#endif
5624 return changed;
5625 }
5626
5627#ifdef DEBUG
5628 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5629 bool expected_changed = false;
5630 for (int i = 0; i < length; i++) {
5631 if (dst[i] == src[i]) continue;
5632 expected_changed = true;
5633 if (dir == ASCII_TO_LOWER) {
5634 ASSERT('A' <= src[i] && src[i] <= 'Z');
5635 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5636 } else {
5637 ASSERT(dir == ASCII_TO_UPPER);
5638 ASSERT('a' <= src[i] && src[i] <= 'z');
5639 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5640 }
5641 }
5642 ASSERT(expected_changed == changed);
5643 }
5644#endif
5645};
5646
5647
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005648struct ToLowerTraits {
5649 typedef unibrow::ToLowercase UnibrowConverter;
5650
lrn@chromium.org303ada72010-10-27 09:33:13 +00005651 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005652};
5653
5654
5655struct ToUpperTraits {
5656 typedef unibrow::ToUppercase UnibrowConverter;
5657
lrn@chromium.org303ada72010-10-27 09:33:13 +00005658 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005659};
5660
5661} // namespace
5662
5663
5664template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005665MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005666 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005667 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005668 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005669 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005670 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005671 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005672
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005673 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005674 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005675 if (length == 0) return s;
5676
5677 // Simpler handling of ascii strings.
5678 //
5679 // NOTE: This assumes that the upper/lower case of an ascii
5680 // character is also ascii. This is currently the case, but it
5681 // might break in the future if we implement more context and locale
5682 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005683 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005684 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005685 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005686 if (!maybe_o->ToObject(&o)) return maybe_o;
5687 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005688 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005689 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005690 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005691 return has_changed_character ? result : s;
5692 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005693
lrn@chromium.org303ada72010-10-27 09:33:13 +00005694 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005695 { MaybeObject* maybe_answer =
5696 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005697 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5698 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005699 if (answer->IsSmi()) {
5700 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005701 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005702 ConvertCaseHelper(isolate,
5703 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005704 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5705 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005706 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005707 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005708}
5709
5710
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005711RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005712 return ConvertCase<ToLowerTraits>(
5713 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005714}
5715
5716
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005717RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005718 return ConvertCase<ToUpperTraits>(
5719 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005720}
5721
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005722
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005723static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5724 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5725}
5726
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005727
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005728RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005729 NoHandleAllocation ha;
5730 ASSERT(args.length() == 3);
5731
5732 CONVERT_CHECKED(String, s, args[0]);
5733 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5734 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5735
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005736 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005737 int length = s->length();
5738
5739 int left = 0;
5740 if (trimLeft) {
5741 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5742 left++;
5743 }
5744 }
5745
5746 int right = length;
5747 if (trimRight) {
5748 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5749 right--;
5750 }
5751 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005752 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005753}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005754
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005755
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005756void FindAsciiStringIndices(Vector<const char> subject,
5757 char pattern,
5758 ZoneList<int>* indices,
5759 unsigned int limit) {
5760 ASSERT(limit > 0);
5761 // Collect indices of pattern in subject using memchr.
5762 // Stop after finding at most limit values.
5763 const char* subject_start = reinterpret_cast<const char*>(subject.start());
5764 const char* subject_end = subject_start + subject.length();
5765 const char* pos = subject_start;
5766 while (limit > 0) {
5767 pos = reinterpret_cast<const char*>(
5768 memchr(pos, pattern, subject_end - pos));
5769 if (pos == NULL) return;
5770 indices->Add(static_cast<int>(pos - subject_start));
5771 pos++;
5772 limit--;
5773 }
5774}
5775
5776
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005777template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005778void FindStringIndices(Isolate* isolate,
5779 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005780 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005781 ZoneList<int>* indices,
5782 unsigned int limit) {
5783 ASSERT(limit > 0);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005784 // Collect indices of pattern in subject.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005785 // Stop after finding at most limit values.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005786 int pattern_length = pattern.length();
5787 int index = 0;
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005788 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005789 while (limit > 0) {
5790 index = search.Search(subject, index);
5791 if (index < 0) return;
5792 indices->Add(index);
5793 index += pattern_length;
5794 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005795 }
5796}
5797
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005798
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005799RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005800 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005801 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005802 CONVERT_ARG_CHECKED(String, subject, 0);
5803 CONVERT_ARG_CHECKED(String, pattern, 1);
5804 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5805
5806 int subject_length = subject->length();
5807 int pattern_length = pattern->length();
5808 RUNTIME_ASSERT(pattern_length > 0);
5809
5810 // The limit can be very large (0xffffffffu), but since the pattern
5811 // isn't empty, we can never create more parts than ~half the length
5812 // of the subject.
5813
5814 if (!subject->IsFlat()) FlattenString(subject);
5815
5816 static const int kMaxInitialListCapacity = 16;
5817
danno@chromium.org40cb8782011-05-25 07:58:50 +00005818 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005819
5820 // Find (up to limit) indices of separator and end-of-string in subject
5821 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5822 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005823 if (!pattern->IsFlat()) FlattenString(pattern);
5824
5825 // No allocation block.
5826 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005827 AssertNoAllocation nogc;
5828 if (subject->IsAsciiRepresentation()) {
5829 Vector<const char> subject_vector = subject->ToAsciiVector();
5830 if (pattern->IsAsciiRepresentation()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005831 Vector<const char> pattern_vector = pattern->ToAsciiVector();
5832 if (pattern_vector.length() == 1) {
5833 FindAsciiStringIndices(subject_vector,
5834 pattern_vector[0],
5835 &indices,
5836 limit);
5837 } else {
5838 FindStringIndices(isolate,
5839 subject_vector,
5840 pattern_vector,
5841 &indices,
5842 limit);
5843 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005844 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005845 FindStringIndices(isolate,
5846 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005847 pattern->ToUC16Vector(),
5848 &indices,
5849 limit);
5850 }
5851 } else {
5852 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5853 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005854 FindStringIndices(isolate,
5855 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005856 pattern->ToAsciiVector(),
5857 &indices,
5858 limit);
5859 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005860 FindStringIndices(isolate,
5861 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005862 pattern->ToUC16Vector(),
5863 &indices,
5864 limit);
5865 }
5866 }
5867 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005868
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005869 if (static_cast<uint32_t>(indices.length()) < limit) {
5870 indices.Add(subject_length);
5871 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005872
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005873 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005874
5875 // Create JSArray of substrings separated by separator.
5876 int part_count = indices.length();
5877
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005878 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005879 result->set_length(Smi::FromInt(part_count));
5880
5881 ASSERT(result->HasFastElements());
5882
5883 if (part_count == 1 && indices.at(0) == subject_length) {
5884 FixedArray::cast(result->elements())->set(0, *subject);
5885 return *result;
5886 }
5887
5888 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5889 int part_start = 0;
5890 for (int i = 0; i < part_count; i++) {
5891 HandleScope local_loop_handle;
5892 int part_end = indices.at(i);
5893 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00005894 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005895 elements->set(i, *substring);
5896 part_start = part_end + pattern_length;
5897 }
5898
5899 return *result;
5900}
5901
5902
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005903// Copies ascii characters to the given fixed array looking up
5904// one-char strings in the cache. Gives up on the first char that is
5905// not in the cache and fills the remainder with smi zeros. Returns
5906// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005907static int CopyCachedAsciiCharsToArray(Heap* heap,
5908 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005909 FixedArray* elements,
5910 int length) {
5911 AssertNoAllocation nogc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005912 FixedArray* ascii_cache = heap->single_character_string_cache();
5913 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005914 int i;
5915 for (i = 0; i < length; ++i) {
5916 Object* value = ascii_cache->get(chars[i]);
5917 if (value == undefined) break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005918 ASSERT(!heap->InNewSpace(value));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005919 elements->set(i, value, SKIP_WRITE_BARRIER);
5920 }
5921 if (i < length) {
5922 ASSERT(Smi::FromInt(0) == 0);
5923 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5924 }
5925#ifdef DEBUG
5926 for (int j = 0; j < length; ++j) {
5927 Object* element = elements->get(j);
5928 ASSERT(element == Smi::FromInt(0) ||
5929 (element->IsString() && String::cast(element)->LooksValid()));
5930 }
5931#endif
5932 return i;
5933}
5934
5935
5936// Converts a String to JSArray.
5937// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005938RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005939 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005940 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005941 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005942 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005943
5944 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005945 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005946
5947 Handle<FixedArray> elements;
5948 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005949 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005950 { MaybeObject* maybe_obj =
5951 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005952 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5953 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005954 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005955
5956 Vector<const char> chars = s->ToAsciiVector();
5957 // Note, this will initialize all elements (not only the prefix)
5958 // to prevent GC from seeing partially initialized array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005959 int num_copied_from_cache = CopyCachedAsciiCharsToArray(isolate->heap(),
5960 chars.start(),
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005961 *elements,
5962 length);
5963
5964 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005965 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5966 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005967 }
5968 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005969 elements = isolate->factory()->NewFixedArray(length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005970 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005971 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5972 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005973 }
5974 }
5975
5976#ifdef DEBUG
5977 for (int i = 0; i < length; ++i) {
5978 ASSERT(String::cast(elements->get(i))->length() == 1);
5979 }
5980#endif
5981
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005982 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005983}
5984
5985
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005986RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005987 NoHandleAllocation ha;
5988 ASSERT(args.length() == 1);
5989 CONVERT_CHECKED(String, value, args[0]);
5990 return value->ToObject();
5991}
5992
5993
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005994bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005995 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005996 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005997 return char_length == 0;
5998}
5999
6000
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006001RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006002 NoHandleAllocation ha;
6003 ASSERT(args.length() == 1);
6004
6005 Object* number = args[0];
6006 RUNTIME_ASSERT(number->IsNumber());
6007
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006008 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006009}
6010
6011
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006012RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006013 NoHandleAllocation ha;
6014 ASSERT(args.length() == 1);
6015
6016 Object* number = args[0];
6017 RUNTIME_ASSERT(number->IsNumber());
6018
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006019 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006020}
6021
6022
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006023RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006024 NoHandleAllocation ha;
6025 ASSERT(args.length() == 1);
6026
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006027 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006028
6029 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6030 if (number > 0 && number <= Smi::kMaxValue) {
6031 return Smi::FromInt(static_cast<int>(number));
6032 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006033 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006034}
6035
6036
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006037RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006038 NoHandleAllocation ha;
6039 ASSERT(args.length() == 1);
6040
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006041 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006042
6043 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6044 if (number > 0 && number <= Smi::kMaxValue) {
6045 return Smi::FromInt(static_cast<int>(number));
6046 }
6047
6048 double double_value = DoubleToInteger(number);
6049 // Map both -0 and +0 to +0.
6050 if (double_value == 0) double_value = 0;
6051
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006052 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006053}
6054
6055
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006056RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006057 NoHandleAllocation ha;
6058 ASSERT(args.length() == 1);
6059
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006060 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006061 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006062}
6063
6064
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006065RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006066 NoHandleAllocation ha;
6067 ASSERT(args.length() == 1);
6068
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006069 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006070
6071 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6072 if (number > 0 && number <= Smi::kMaxValue) {
6073 return Smi::FromInt(static_cast<int>(number));
6074 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006075 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006076}
6077
6078
ager@chromium.org870a0b62008-11-04 11:43:05 +00006079// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6080// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006081RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006082 NoHandleAllocation ha;
6083 ASSERT(args.length() == 1);
6084
6085 Object* obj = args[0];
6086 if (obj->IsSmi()) {
6087 return obj;
6088 }
6089 if (obj->IsHeapNumber()) {
6090 double value = HeapNumber::cast(obj)->value();
6091 int int_value = FastD2I(value);
6092 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6093 return Smi::FromInt(int_value);
6094 }
6095 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006096 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006097}
6098
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006099
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006100RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006101 NoHandleAllocation ha;
6102 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006103 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006104}
6105
6106
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006107RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006108 NoHandleAllocation ha;
6109 ASSERT(args.length() == 2);
6110
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006111 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6112 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006113 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006114}
6115
6116
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006117RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006118 NoHandleAllocation ha;
6119 ASSERT(args.length() == 2);
6120
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006121 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6122 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006123 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006124}
6125
6126
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006127RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006128 NoHandleAllocation ha;
6129 ASSERT(args.length() == 2);
6130
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006131 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6132 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006133 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006134}
6135
6136
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006137RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006138 NoHandleAllocation ha;
6139 ASSERT(args.length() == 1);
6140
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006141 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006142 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006143}
6144
6145
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006146RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006147 NoHandleAllocation ha;
6148 ASSERT(args.length() == 0);
6149
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006150 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006151}
6152
6153
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006154RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006155 NoHandleAllocation ha;
6156 ASSERT(args.length() == 2);
6157
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006158 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6159 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006160 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006161}
6162
6163
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006164RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006165 NoHandleAllocation ha;
6166 ASSERT(args.length() == 2);
6167
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006168 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6169 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006170
ager@chromium.org3811b432009-10-28 14:53:37 +00006171 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006172 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006173 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006174}
6175
6176
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006177RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006178 NoHandleAllocation ha;
6179 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006180 CONVERT_CHECKED(String, str1, args[0]);
6181 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006182 isolate->counters()->string_add_runtime()->Increment();
6183 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006184}
6185
6186
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006187template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006188static inline void StringBuilderConcatHelper(String* special,
6189 sinkchar* sink,
6190 FixedArray* fixed_array,
6191 int array_length) {
6192 int position = 0;
6193 for (int i = 0; i < array_length; i++) {
6194 Object* element = fixed_array->get(i);
6195 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006196 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006197 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006198 int pos;
6199 int len;
6200 if (encoded_slice > 0) {
6201 // Position and length encoded in one smi.
6202 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6203 len = StringBuilderSubstringLength::decode(encoded_slice);
6204 } else {
6205 // Position and length encoded in two smis.
6206 Object* obj = fixed_array->get(++i);
6207 ASSERT(obj->IsSmi());
6208 pos = Smi::cast(obj)->value();
6209 len = -encoded_slice;
6210 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006211 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006212 sink + position,
6213 pos,
6214 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006215 position += len;
6216 } else {
6217 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006218 int element_length = string->length();
6219 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006220 position += element_length;
6221 }
6222 }
6223}
6224
6225
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006226RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006227 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006228 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006229 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006230 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006231 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006232 return Failure::OutOfMemoryException();
6233 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006234 int array_length = args.smi_at(1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006235 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006236
6237 // This assumption is used by the slice encoding in one or two smis.
6238 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6239
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006240 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006241 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006242 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006243 }
6244 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006245 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006246 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006247 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006248
6249 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006250 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006251 } else if (array_length == 1) {
6252 Object* first = fixed_array->get(0);
6253 if (first->IsString()) return first;
6254 }
6255
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006256 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006257 int position = 0;
6258 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006259 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006260 Object* elt = fixed_array->get(i);
6261 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006262 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006263 int smi_value = Smi::cast(elt)->value();
6264 int pos;
6265 int len;
6266 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006267 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006268 pos = StringBuilderSubstringPosition::decode(smi_value);
6269 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006270 } else {
6271 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006272 len = -smi_value;
6273 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006274 i++;
6275 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006276 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006277 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006278 Object* next_smi = fixed_array->get(i);
6279 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006280 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006281 }
6282 pos = Smi::cast(next_smi)->value();
6283 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006284 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006285 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006286 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006287 ASSERT(pos >= 0);
6288 ASSERT(len >= 0);
6289 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006290 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006291 }
6292 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006293 } else if (elt->IsString()) {
6294 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006295 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006296 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006297 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006298 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006299 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006300 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006301 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006302 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006303 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006304 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006305 return Failure::OutOfMemoryException();
6306 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006307 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006308 }
6309
6310 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006311 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006312
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006313 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006314 { MaybeObject* maybe_object =
6315 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006316 if (!maybe_object->ToObject(&object)) return maybe_object;
6317 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006318 SeqAsciiString* answer = SeqAsciiString::cast(object);
6319 StringBuilderConcatHelper(special,
6320 answer->GetChars(),
6321 fixed_array,
6322 array_length);
6323 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006324 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006325 { MaybeObject* maybe_object =
6326 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006327 if (!maybe_object->ToObject(&object)) return maybe_object;
6328 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006329 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6330 StringBuilderConcatHelper(special,
6331 answer->GetChars(),
6332 fixed_array,
6333 array_length);
6334 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006335 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006336}
6337
6338
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006339RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006340 NoHandleAllocation ha;
6341 ASSERT(args.length() == 3);
6342 CONVERT_CHECKED(JSArray, array, args[0]);
6343 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006344 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006345 return Failure::OutOfMemoryException();
6346 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006347 int array_length = args.smi_at(1);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006348 CONVERT_CHECKED(String, separator, args[2]);
6349
6350 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006351 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006352 }
6353 FixedArray* fixed_array = FixedArray::cast(array->elements());
6354 if (fixed_array->length() < array_length) {
6355 array_length = fixed_array->length();
6356 }
6357
6358 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006359 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006360 } else if (array_length == 1) {
6361 Object* first = fixed_array->get(0);
6362 if (first->IsString()) return first;
6363 }
6364
6365 int separator_length = separator->length();
6366 int max_nof_separators =
6367 (String::kMaxLength + separator_length - 1) / separator_length;
6368 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006369 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006370 return Failure::OutOfMemoryException();
6371 }
6372 int length = (array_length - 1) * separator_length;
6373 for (int i = 0; i < array_length; i++) {
6374 Object* element_obj = fixed_array->get(i);
6375 if (!element_obj->IsString()) {
6376 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006377 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006378 }
6379 String* element = String::cast(element_obj);
6380 int increment = element->length();
6381 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006382 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006383 return Failure::OutOfMemoryException();
6384 }
6385 length += increment;
6386 }
6387
6388 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006389 { MaybeObject* maybe_object =
6390 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006391 if (!maybe_object->ToObject(&object)) return maybe_object;
6392 }
6393 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6394
6395 uc16* sink = answer->GetChars();
6396#ifdef DEBUG
6397 uc16* end = sink + length;
6398#endif
6399
6400 String* first = String::cast(fixed_array->get(0));
6401 int first_length = first->length();
6402 String::WriteToFlat(first, sink, 0, first_length);
6403 sink += first_length;
6404
6405 for (int i = 1; i < array_length; i++) {
6406 ASSERT(sink + separator_length <= end);
6407 String::WriteToFlat(separator, sink, 0, separator_length);
6408 sink += separator_length;
6409
6410 String* element = String::cast(fixed_array->get(i));
6411 int element_length = element->length();
6412 ASSERT(sink + element_length <= end);
6413 String::WriteToFlat(element, sink, 0, element_length);
6414 sink += element_length;
6415 }
6416 ASSERT(sink == end);
6417
6418 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6419 return answer;
6420}
6421
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006422template <typename Char>
6423static void JoinSparseArrayWithSeparator(FixedArray* elements,
6424 int elements_length,
6425 uint32_t array_length,
6426 String* separator,
6427 Vector<Char> buffer) {
6428 int previous_separator_position = 0;
6429 int separator_length = separator->length();
6430 int cursor = 0;
6431 for (int i = 0; i < elements_length; i += 2) {
6432 int position = NumberToInt32(elements->get(i));
6433 String* string = String::cast(elements->get(i + 1));
6434 int string_length = string->length();
6435 if (string->length() > 0) {
6436 while (previous_separator_position < position) {
6437 String::WriteToFlat<Char>(separator, &buffer[cursor],
6438 0, separator_length);
6439 cursor += separator_length;
6440 previous_separator_position++;
6441 }
6442 String::WriteToFlat<Char>(string, &buffer[cursor],
6443 0, string_length);
6444 cursor += string->length();
6445 }
6446 }
6447 if (separator_length > 0) {
6448 // Array length must be representable as a signed 32-bit number,
6449 // otherwise the total string length would have been too large.
6450 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6451 int last_array_index = static_cast<int>(array_length - 1);
6452 while (previous_separator_position < last_array_index) {
6453 String::WriteToFlat<Char>(separator, &buffer[cursor],
6454 0, separator_length);
6455 cursor += separator_length;
6456 previous_separator_position++;
6457 }
6458 }
6459 ASSERT(cursor <= buffer.length());
6460}
6461
6462
6463RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6464 NoHandleAllocation ha;
6465 ASSERT(args.length() == 3);
6466 CONVERT_CHECKED(JSArray, elements_array, args[0]);
6467 RUNTIME_ASSERT(elements_array->HasFastElements());
6468 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6469 CONVERT_CHECKED(String, separator, args[2]);
6470 // elements_array is fast-mode JSarray of alternating positions
6471 // (increasing order) and strings.
6472 // array_length is length of original array (used to add separators);
6473 // separator is string to put between elements. Assumed to be non-empty.
6474
6475 // Find total length of join result.
6476 int string_length = 0;
6477 bool is_ascii = true;
6478 int max_string_length = SeqAsciiString::kMaxLength;
6479 bool overflow = false;
6480 CONVERT_NUMBER_CHECKED(int, elements_length,
6481 Int32, elements_array->length());
6482 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6483 FixedArray* elements = FixedArray::cast(elements_array->elements());
6484 for (int i = 0; i < elements_length; i += 2) {
6485 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6486 CONVERT_CHECKED(String, string, elements->get(i + 1));
6487 int length = string->length();
6488 if (is_ascii && !string->IsAsciiRepresentation()) {
6489 is_ascii = false;
6490 max_string_length = SeqTwoByteString::kMaxLength;
6491 }
6492 if (length > max_string_length ||
6493 max_string_length - length < string_length) {
6494 overflow = true;
6495 break;
6496 }
6497 string_length += length;
6498 }
6499 int separator_length = separator->length();
6500 if (!overflow && separator_length > 0) {
6501 if (array_length <= 0x7fffffffu) {
6502 int separator_count = static_cast<int>(array_length) - 1;
6503 int remaining_length = max_string_length - string_length;
6504 if ((remaining_length / separator_length) >= separator_count) {
6505 string_length += separator_length * (array_length - 1);
6506 } else {
6507 // Not room for the separators within the maximal string length.
6508 overflow = true;
6509 }
6510 } else {
6511 // Nonempty separator and at least 2^31-1 separators necessary
6512 // means that the string is too large to create.
6513 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6514 overflow = true;
6515 }
6516 }
6517 if (overflow) {
6518 // Throw OutOfMemory exception for creating too large a string.
6519 V8::FatalProcessOutOfMemory("Array join result too large.");
6520 }
6521
6522 if (is_ascii) {
6523 MaybeObject* result_allocation =
6524 isolate->heap()->AllocateRawAsciiString(string_length);
6525 if (result_allocation->IsFailure()) return result_allocation;
6526 SeqAsciiString* result_string =
6527 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6528 JoinSparseArrayWithSeparator<char>(elements,
6529 elements_length,
6530 array_length,
6531 separator,
6532 Vector<char>(result_string->GetChars(),
6533 string_length));
6534 return result_string;
6535 } else {
6536 MaybeObject* result_allocation =
6537 isolate->heap()->AllocateRawTwoByteString(string_length);
6538 if (result_allocation->IsFailure()) return result_allocation;
6539 SeqTwoByteString* result_string =
6540 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6541 JoinSparseArrayWithSeparator<uc16>(elements,
6542 elements_length,
6543 array_length,
6544 separator,
6545 Vector<uc16>(result_string->GetChars(),
6546 string_length));
6547 return result_string;
6548 }
6549}
6550
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006551
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006552RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006553 NoHandleAllocation ha;
6554 ASSERT(args.length() == 2);
6555
6556 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6557 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006558 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006559}
6560
6561
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006562RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006563 NoHandleAllocation ha;
6564 ASSERT(args.length() == 2);
6565
6566 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6567 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006568 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006569}
6570
6571
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006572RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006573 NoHandleAllocation ha;
6574 ASSERT(args.length() == 2);
6575
6576 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6577 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006578 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006579}
6580
6581
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006582RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006583 NoHandleAllocation ha;
6584 ASSERT(args.length() == 1);
6585
6586 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006587 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006588}
6589
6590
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006591RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006592 NoHandleAllocation ha;
6593 ASSERT(args.length() == 2);
6594
6595 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6596 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006597 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006598}
6599
6600
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006601RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006602 NoHandleAllocation ha;
6603 ASSERT(args.length() == 2);
6604
6605 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6606 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006607 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006608}
6609
6610
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006611RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006612 NoHandleAllocation ha;
6613 ASSERT(args.length() == 2);
6614
6615 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6616 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006617 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006618}
6619
6620
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006621RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006622 NoHandleAllocation ha;
6623 ASSERT(args.length() == 2);
6624
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006625 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6626 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006627 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6628 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6629 if (x == y) return Smi::FromInt(EQUAL);
6630 Object* result;
6631 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6632 result = Smi::FromInt(EQUAL);
6633 } else {
6634 result = Smi::FromInt(NOT_EQUAL);
6635 }
6636 return result;
6637}
6638
6639
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006640RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006641 NoHandleAllocation ha;
6642 ASSERT(args.length() == 2);
6643
6644 CONVERT_CHECKED(String, x, args[0]);
6645 CONVERT_CHECKED(String, y, args[1]);
6646
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006647 bool not_equal = !x->Equals(y);
6648 // This is slightly convoluted because the value that signifies
6649 // equality is 0 and inequality is 1 so we have to negate the result
6650 // from String::Equals.
6651 ASSERT(not_equal == 0 || not_equal == 1);
6652 STATIC_CHECK(EQUAL == 0);
6653 STATIC_CHECK(NOT_EQUAL == 1);
6654 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006655}
6656
6657
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006658RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006659 NoHandleAllocation ha;
6660 ASSERT(args.length() == 3);
6661
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006662 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6663 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006664 if (isnan(x) || isnan(y)) return args[2];
6665 if (x == y) return Smi::FromInt(EQUAL);
6666 if (isless(x, y)) return Smi::FromInt(LESS);
6667 return Smi::FromInt(GREATER);
6668}
6669
6670
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006671// Compare two Smis as if they were converted to strings and then
6672// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006673RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006674 NoHandleAllocation ha;
6675 ASSERT(args.length() == 2);
6676
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006677 // Extract the integer values from the Smis.
6678 CONVERT_CHECKED(Smi, x, args[0]);
6679 CONVERT_CHECKED(Smi, y, args[1]);
6680 int x_value = x->value();
6681 int y_value = y->value();
6682
6683 // If the integers are equal so are the string representations.
6684 if (x_value == y_value) return Smi::FromInt(EQUAL);
6685
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006686 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006687 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006688 if (x_value == 0 || y_value == 0)
6689 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006690
ager@chromium.org32912102009-01-16 10:38:43 +00006691 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006692 // smallest because the char code of '-' is less than the char code
6693 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006694
6695 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
6696 // architectures using 32-bit Smis.
6697 uint32_t x_scaled = x_value;
6698 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006699 if (x_value < 0 || y_value < 0) {
6700 if (y_value >= 0) return Smi::FromInt(LESS);
6701 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006702 x_scaled = -x_value;
6703 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006704 }
6705
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006706 static const uint32_t kPowersOf10[] = {
6707 1, 10, 100, 1000, 10*1000, 100*1000,
6708 1000*1000, 10*1000*1000, 100*1000*1000,
6709 1000*1000*1000
6710 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006711
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006712 // If the integers have the same number of decimal digits they can be
6713 // compared directly as the numeric order is the same as the
6714 // lexicographic order. If one integer has fewer digits, it is scaled
6715 // by some power of 10 to have the same number of digits as the longer
6716 // integer. If the scaled integers are equal it means the shorter
6717 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006718
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006719 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
6720 int x_log2 = IntegerLog2(x_scaled);
6721 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
6722 x_log10 -= x_scaled < kPowersOf10[x_log10];
6723
6724 int y_log2 = IntegerLog2(y_scaled);
6725 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
6726 y_log10 -= y_scaled < kPowersOf10[y_log10];
6727
6728 int tie = EQUAL;
6729
6730 if (x_log10 < y_log10) {
6731 // X has fewer digits. We would like to simply scale up X but that
6732 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
6733 // be scaled up to 9_000_000_000. So we scale up by the next
6734 // smallest power and scale down Y to drop one digit. It is OK to
6735 // drop one digit from the longer integer since the final digit is
6736 // past the length of the shorter integer.
6737 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
6738 y_scaled /= 10;
6739 tie = LESS;
6740 } else if (y_log10 < x_log10) {
6741 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
6742 x_scaled /= 10;
6743 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006744 }
6745
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006746 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
6747 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
6748 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006749}
6750
6751
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006752static Object* StringInputBufferCompare(RuntimeState* state,
6753 String* x,
6754 String* y) {
6755 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
6756 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006757 bufx.Reset(x);
6758 bufy.Reset(y);
6759 while (bufx.has_more() && bufy.has_more()) {
6760 int d = bufx.GetNext() - bufy.GetNext();
6761 if (d < 0) return Smi::FromInt(LESS);
6762 else if (d > 0) return Smi::FromInt(GREATER);
6763 }
6764
6765 // x is (non-trivial) prefix of y:
6766 if (bufy.has_more()) return Smi::FromInt(LESS);
6767 // y is prefix of x:
6768 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6769}
6770
6771
6772static Object* FlatStringCompare(String* x, String* y) {
6773 ASSERT(x->IsFlat());
6774 ASSERT(y->IsFlat());
6775 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6776 int prefix_length = x->length();
6777 if (y->length() < prefix_length) {
6778 prefix_length = y->length();
6779 equal_prefix_result = Smi::FromInt(GREATER);
6780 } else if (y->length() > prefix_length) {
6781 equal_prefix_result = Smi::FromInt(LESS);
6782 }
6783 int r;
6784 if (x->IsAsciiRepresentation()) {
6785 Vector<const char> x_chars = x->ToAsciiVector();
6786 if (y->IsAsciiRepresentation()) {
6787 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006788 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006789 } else {
6790 Vector<const uc16> y_chars = y->ToUC16Vector();
6791 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6792 }
6793 } else {
6794 Vector<const uc16> x_chars = x->ToUC16Vector();
6795 if (y->IsAsciiRepresentation()) {
6796 Vector<const char> y_chars = y->ToAsciiVector();
6797 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6798 } else {
6799 Vector<const uc16> y_chars = y->ToUC16Vector();
6800 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6801 }
6802 }
6803 Object* result;
6804 if (r == 0) {
6805 result = equal_prefix_result;
6806 } else {
6807 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6808 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006809 ASSERT(result ==
6810 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006811 return result;
6812}
6813
6814
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006815RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006816 NoHandleAllocation ha;
6817 ASSERT(args.length() == 2);
6818
6819 CONVERT_CHECKED(String, x, args[0]);
6820 CONVERT_CHECKED(String, y, args[1]);
6821
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006822 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006823
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006824 // A few fast case tests before we flatten.
6825 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006826 if (y->length() == 0) {
6827 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006828 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006829 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006830 return Smi::FromInt(LESS);
6831 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006832
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006833 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006834 if (d < 0) return Smi::FromInt(LESS);
6835 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006836
lrn@chromium.org303ada72010-10-27 09:33:13 +00006837 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006838 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006839 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6840 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006841 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006842 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6843 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006844
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006845 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006846 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006847}
6848
6849
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006850RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006851 NoHandleAllocation ha;
6852 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006853 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006854
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006855 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006856 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006857}
6858
6859
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006860RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006861 NoHandleAllocation ha;
6862 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006863 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006864
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006865 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006866 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006867}
6868
6869
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006870RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006871 NoHandleAllocation ha;
6872 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006873 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006874
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006875 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006876 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006877}
6878
6879
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006880static const double kPiDividedBy4 = 0.78539816339744830962;
6881
6882
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006883RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006884 NoHandleAllocation ha;
6885 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006886 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006887
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006888 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6889 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006890 double result;
6891 if (isinf(x) && isinf(y)) {
6892 // Make sure that the result in case of two infinite arguments
6893 // is a multiple of Pi / 4. The sign of the result is determined
6894 // by the first argument (x) and the sign of the second argument
6895 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006896 int multiplier = (x < 0) ? -1 : 1;
6897 if (y < 0) multiplier *= 3;
6898 result = multiplier * kPiDividedBy4;
6899 } else {
6900 result = atan2(x, y);
6901 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006902 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006903}
6904
6905
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006906RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006907 NoHandleAllocation ha;
6908 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006909 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006910
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006911 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006912 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006913}
6914
6915
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006916RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006917 NoHandleAllocation ha;
6918 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006919 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006920
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006921 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006922 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006923}
6924
6925
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006926RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006927 NoHandleAllocation ha;
6928 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006929 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006930
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006931 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006932 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006933}
6934
6935
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006936RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006937 NoHandleAllocation ha;
6938 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006939 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006940
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006941 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006942 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006943}
6944
6945
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006946RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006947 NoHandleAllocation ha;
6948 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006949 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006950
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006951 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006952 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006953}
6954
6955
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006956RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006957 NoHandleAllocation ha;
6958 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006959 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006960
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006961 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006962
6963 // If the second argument is a smi, it is much faster to call the
6964 // custom powi() function than the generic pow().
6965 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006966 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006967 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006968 }
6969
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006970 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006971 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006972}
6973
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006974// Fast version of Math.pow if we know that y is not an integer and
6975// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006976RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006977 NoHandleAllocation ha;
6978 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006979 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6980 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006981 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006982 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006983 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006984 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006985 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006986 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006987 }
6988}
6989
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006990
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006991RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006992 NoHandleAllocation ha;
6993 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006994 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006995
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006996 if (!args[0]->IsHeapNumber()) {
6997 // Must be smi. Return the argument unchanged for all the other types
6998 // to make fuzz-natives test happy.
6999 return args[0];
7000 }
7001
7002 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7003
7004 double value = number->value();
7005 int exponent = number->get_exponent();
7006 int sign = number->get_sign();
7007
danno@chromium.org160a7b02011-04-18 15:51:38 +00007008 if (exponent < -1) {
7009 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7010 if (sign) return isolate->heap()->minus_zero_value();
7011 return Smi::FromInt(0);
7012 }
7013
7014 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7015 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
7016 // agument holds for 32-bit smis).
7017 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007018 return Smi::FromInt(static_cast<int>(value + 0.5));
7019 }
7020
7021 // If the magnitude is big enough, there's no place for fraction part. If we
7022 // try to add 0.5 to this number, 1.0 will be added instead.
7023 if (exponent >= 52) {
7024 return number;
7025 }
7026
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007027 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007028
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007029 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007030 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007031}
7032
7033
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007034RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007035 NoHandleAllocation ha;
7036 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007037 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007038
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007039 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007040 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007041}
7042
7043
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007044RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007045 NoHandleAllocation ha;
7046 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007047 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007048
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007049 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007050 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007051}
7052
7053
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007054RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007055 NoHandleAllocation ha;
7056 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007057 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007058
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007059 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007060 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007061}
7062
7063
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007064static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007065 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7066 181, 212, 243, 273, 304, 334};
7067 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7068 182, 213, 244, 274, 305, 335};
7069
7070 year += month / 12;
7071 month %= 12;
7072 if (month < 0) {
7073 year--;
7074 month += 12;
7075 }
7076
7077 ASSERT(month >= 0);
7078 ASSERT(month < 12);
7079
7080 // year_delta is an arbitrary number such that:
7081 // a) year_delta = -1 (mod 400)
7082 // b) year + year_delta > 0 for years in the range defined by
7083 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7084 // Jan 1 1970. This is required so that we don't run into integer
7085 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007086 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007087 // operations.
7088 static const int year_delta = 399999;
7089 static const int base_day = 365 * (1970 + year_delta) +
7090 (1970 + year_delta) / 4 -
7091 (1970 + year_delta) / 100 +
7092 (1970 + year_delta) / 400;
7093
7094 int year1 = year + year_delta;
7095 int day_from_year = 365 * year1 +
7096 year1 / 4 -
7097 year1 / 100 +
7098 year1 / 400 -
7099 base_day;
7100
7101 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007102 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007103 }
7104
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007105 return day_from_year + day_from_month_leap[month] + day - 1;
7106}
7107
7108
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007109RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007110 NoHandleAllocation ha;
7111 ASSERT(args.length() == 3);
7112
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007113 CONVERT_SMI_ARG_CHECKED(year, 0);
7114 CONVERT_SMI_ARG_CHECKED(month, 1);
7115 CONVERT_SMI_ARG_CHECKED(date, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007116
7117 return Smi::FromInt(MakeDay(year, month, date));
7118}
7119
7120
7121static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7122static const int kDaysIn4Years = 4 * 365 + 1;
7123static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7124static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7125static const int kDays1970to2000 = 30 * 365 + 7;
7126static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7127 kDays1970to2000;
7128static const int kYearsOffset = 400000;
7129
7130static const char kDayInYear[] = {
7131 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7132 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7133 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7134 22, 23, 24, 25, 26, 27, 28,
7135 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7136 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7137 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7138 22, 23, 24, 25, 26, 27, 28, 29, 30,
7139 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7140 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7141 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7142 22, 23, 24, 25, 26, 27, 28, 29, 30,
7143 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7144 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7145 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7146 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7147 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7148 22, 23, 24, 25, 26, 27, 28, 29, 30,
7149 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7150 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7151 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7152 22, 23, 24, 25, 26, 27, 28, 29, 30,
7153 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7154 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7155
7156 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7157 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7158 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7159 22, 23, 24, 25, 26, 27, 28,
7160 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7161 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7162 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7163 22, 23, 24, 25, 26, 27, 28, 29, 30,
7164 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7165 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7166 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7167 22, 23, 24, 25, 26, 27, 28, 29, 30,
7168 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7169 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7170 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7171 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7172 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7173 22, 23, 24, 25, 26, 27, 28, 29, 30,
7174 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7175 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7176 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7177 22, 23, 24, 25, 26, 27, 28, 29, 30,
7178 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7179 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7180
7181 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7182 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7183 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7184 22, 23, 24, 25, 26, 27, 28, 29,
7185 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7186 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7187 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7188 22, 23, 24, 25, 26, 27, 28, 29, 30,
7189 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7190 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7191 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7192 22, 23, 24, 25, 26, 27, 28, 29, 30,
7193 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7194 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7195 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7196 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7197 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7198 22, 23, 24, 25, 26, 27, 28, 29, 30,
7199 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7200 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7201 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7202 22, 23, 24, 25, 26, 27, 28, 29, 30,
7203 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7204 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7205
7206 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7207 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7208 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7209 22, 23, 24, 25, 26, 27, 28,
7210 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7211 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7212 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7213 22, 23, 24, 25, 26, 27, 28, 29, 30,
7214 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7215 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7216 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7217 22, 23, 24, 25, 26, 27, 28, 29, 30,
7218 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7219 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7220 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7221 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7222 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7223 22, 23, 24, 25, 26, 27, 28, 29, 30,
7224 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7225 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7226 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7227 22, 23, 24, 25, 26, 27, 28, 29, 30,
7228 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7229 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7230
7231static const char kMonthInYear[] = {
7232 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7233 0, 0, 0, 0, 0, 0,
7234 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7235 1, 1, 1,
7236 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7237 2, 2, 2, 2, 2, 2,
7238 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7239 3, 3, 3, 3, 3,
7240 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7241 4, 4, 4, 4, 4, 4,
7242 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7243 5, 5, 5, 5, 5,
7244 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7245 6, 6, 6, 6, 6, 6,
7246 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7247 7, 7, 7, 7, 7, 7,
7248 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7249 8, 8, 8, 8, 8,
7250 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7251 9, 9, 9, 9, 9, 9,
7252 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7253 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7254 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7255 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7256
7257 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7258 0, 0, 0, 0, 0, 0,
7259 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7260 1, 1, 1,
7261 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7262 2, 2, 2, 2, 2, 2,
7263 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7264 3, 3, 3, 3, 3,
7265 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7266 4, 4, 4, 4, 4, 4,
7267 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7268 5, 5, 5, 5, 5,
7269 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7270 6, 6, 6, 6, 6, 6,
7271 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7272 7, 7, 7, 7, 7, 7,
7273 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7274 8, 8, 8, 8, 8,
7275 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7276 9, 9, 9, 9, 9, 9,
7277 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7278 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7279 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7280 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7281
7282 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7283 0, 0, 0, 0, 0, 0,
7284 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7285 1, 1, 1, 1,
7286 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7287 2, 2, 2, 2, 2, 2,
7288 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7289 3, 3, 3, 3, 3,
7290 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7291 4, 4, 4, 4, 4, 4,
7292 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7293 5, 5, 5, 5, 5,
7294 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7295 6, 6, 6, 6, 6, 6,
7296 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7297 7, 7, 7, 7, 7, 7,
7298 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7299 8, 8, 8, 8, 8,
7300 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7301 9, 9, 9, 9, 9, 9,
7302 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7303 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7304 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7305 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7306
7307 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7308 0, 0, 0, 0, 0, 0,
7309 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7310 1, 1, 1,
7311 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7312 2, 2, 2, 2, 2, 2,
7313 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7314 3, 3, 3, 3, 3,
7315 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7316 4, 4, 4, 4, 4, 4,
7317 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7318 5, 5, 5, 5, 5,
7319 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7320 6, 6, 6, 6, 6, 6,
7321 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7322 7, 7, 7, 7, 7, 7,
7323 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7324 8, 8, 8, 8, 8,
7325 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7326 9, 9, 9, 9, 9, 9,
7327 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7328 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7329 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7330 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7331
7332
7333// This function works for dates from 1970 to 2099.
7334static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007335 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007336#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007337 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007338#endif
7339
7340 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7341 date %= kDaysIn4Years;
7342
7343 month = kMonthInYear[date];
7344 day = kDayInYear[date];
7345
7346 ASSERT(MakeDay(year, month, day) == save_date);
7347}
7348
7349
7350static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007351 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007352#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007353 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007354#endif
7355
7356 date += kDaysOffset;
7357 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7358 date %= kDaysIn400Years;
7359
7360 ASSERT(MakeDay(year, 0, 1) + date == save_date);
7361
7362 date--;
7363 int yd1 = date / kDaysIn100Years;
7364 date %= kDaysIn100Years;
7365 year += 100 * yd1;
7366
7367 date++;
7368 int yd2 = date / kDaysIn4Years;
7369 date %= kDaysIn4Years;
7370 year += 4 * yd2;
7371
7372 date--;
7373 int yd3 = date / 365;
7374 date %= 365;
7375 year += yd3;
7376
7377 bool is_leap = (!yd1 || yd2) && !yd3;
7378
7379 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007380 ASSERT(is_leap || (date >= 0));
7381 ASSERT((date < 365) || (is_leap && (date < 366)));
7382 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
7383 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
7384 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007385
7386 if (is_leap) {
7387 day = kDayInYear[2*365 + 1 + date];
7388 month = kMonthInYear[2*365 + 1 + date];
7389 } else {
7390 day = kDayInYear[date];
7391 month = kMonthInYear[date];
7392 }
7393
7394 ASSERT(MakeDay(year, month, day) == save_date);
7395}
7396
7397
7398static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007399 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007400 if (date >= 0 && date < 32 * kDaysIn4Years) {
7401 DateYMDFromTimeAfter1970(date, year, month, day);
7402 } else {
7403 DateYMDFromTimeSlow(date, year, month, day);
7404 }
7405}
7406
7407
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007408RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007409 NoHandleAllocation ha;
7410 ASSERT(args.length() == 2);
7411
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007412 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007413 CONVERT_CHECKED(JSArray, res_array, args[1]);
7414
7415 int year, month, day;
7416 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7417
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007418 RUNTIME_ASSERT(res_array->elements()->map() ==
7419 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007420 FixedArray* elms = FixedArray::cast(res_array->elements());
7421 RUNTIME_ASSERT(elms->length() == 3);
7422
7423 elms->set(0, Smi::FromInt(year));
7424 elms->set(1, Smi::FromInt(month));
7425 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007426
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007427 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007428}
7429
7430
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007431RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007432 HandleScope scope(isolate);
7433 ASSERT(args.length() == 3);
7434
7435 Handle<JSFunction> callee = args.at<JSFunction>(0);
7436 Object** parameters = reinterpret_cast<Object**>(args[1]);
7437 const int argument_count = Smi::cast(args[2])->value();
7438
7439 Handle<JSObject> result =
7440 isolate->factory()->NewArgumentsObject(callee, argument_count);
7441 // Allocate the elements if needed.
7442 int parameter_count = callee->shared()->formal_parameter_count();
7443 if (argument_count > 0) {
7444 if (parameter_count > 0) {
7445 int mapped_count = Min(argument_count, parameter_count);
7446 Handle<FixedArray> parameter_map =
7447 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7448 parameter_map->set_map(
7449 isolate->heap()->non_strict_arguments_elements_map());
7450
7451 Handle<Map> old_map(result->map());
7452 Handle<Map> new_map =
7453 isolate->factory()->CopyMapDropTransitions(old_map);
7454 new_map->set_elements_kind(JSObject::NON_STRICT_ARGUMENTS_ELEMENTS);
7455
7456 result->set_map(*new_map);
7457 result->set_elements(*parameter_map);
7458
7459 // Store the context and the arguments array at the beginning of the
7460 // parameter map.
7461 Handle<Context> context(isolate->context());
7462 Handle<FixedArray> arguments =
7463 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7464 parameter_map->set(0, *context);
7465 parameter_map->set(1, *arguments);
7466
7467 // Loop over the actual parameters backwards.
7468 int index = argument_count - 1;
7469 while (index >= mapped_count) {
7470 // These go directly in the arguments array and have no
7471 // corresponding slot in the parameter map.
7472 arguments->set(index, *(parameters - index - 1));
7473 --index;
7474 }
7475
7476 ScopeInfo<> scope_info(callee->shared()->scope_info());
7477 while (index >= 0) {
7478 // Detect duplicate names to the right in the parameter list.
7479 Handle<String> name = scope_info.parameter_name(index);
7480 int context_slot_count = scope_info.number_of_context_slots();
7481 bool duplicate = false;
7482 for (int j = index + 1; j < parameter_count; ++j) {
7483 if (scope_info.parameter_name(j).is_identical_to(name)) {
7484 duplicate = true;
7485 break;
7486 }
7487 }
7488
7489 if (duplicate) {
7490 // This goes directly in the arguments array with a hole in the
7491 // parameter map.
7492 arguments->set(index, *(parameters - index - 1));
7493 parameter_map->set_the_hole(index + 2);
7494 } else {
7495 // The context index goes in the parameter map with a hole in the
7496 // arguments array.
7497 int context_index = -1;
7498 for (int j = Context::MIN_CONTEXT_SLOTS;
7499 j < context_slot_count;
7500 ++j) {
7501 if (scope_info.context_slot_name(j).is_identical_to(name)) {
7502 context_index = j;
7503 break;
7504 }
7505 }
7506 ASSERT(context_index >= 0);
7507 arguments->set_the_hole(index);
7508 parameter_map->set(index + 2, Smi::FromInt(context_index));
7509 }
7510
7511 --index;
7512 }
7513 } else {
7514 // If there is no aliasing, the arguments object elements are not
7515 // special in any way.
7516 Handle<FixedArray> elements =
7517 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7518 result->set_elements(*elements);
7519 for (int i = 0; i < argument_count; ++i) {
7520 elements->set(i, *(parameters - i - 1));
7521 }
7522 }
7523 }
7524 return *result;
7525}
7526
7527
7528RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007529 NoHandleAllocation ha;
7530 ASSERT(args.length() == 3);
7531
7532 JSFunction* callee = JSFunction::cast(args[0]);
7533 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007534 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007535
lrn@chromium.org303ada72010-10-27 09:33:13 +00007536 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007537 { MaybeObject* maybe_result =
7538 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007539 if (!maybe_result->ToObject(&result)) return maybe_result;
7540 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007541 // Allocate the elements if needed.
7542 if (length > 0) {
7543 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007544 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007545 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007546 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7547 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007548
7549 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007550 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007551 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007552 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007553
7554 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007555 for (int i = 0; i < length; i++) {
7556 array->set(i, *--parameters, mode);
7557 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007558 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007559 }
7560 return result;
7561}
7562
7563
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007564RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007565 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007566 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007567 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007568 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007569 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007570
whesse@chromium.org7b260152011-06-20 15:33:18 +00007571 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007572 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007573 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007574 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007575 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7576 context,
7577 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007578 return *result;
7579}
7580
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007581
7582static SmartPointer<Object**> GetNonBoundArguments(int bound_argc,
7583 int* total_argc) {
7584 // Find frame containing arguments passed to the caller.
7585 JavaScriptFrameIterator it;
7586 JavaScriptFrame* frame = it.frame();
7587 List<JSFunction*> functions(2);
7588 frame->GetFunctions(&functions);
7589 if (functions.length() > 1) {
7590 int inlined_frame_index = functions.length() - 1;
7591 JSFunction* inlined_function = functions[inlined_frame_index];
7592 int args_count = inlined_function->shared()->formal_parameter_count();
7593 ScopedVector<SlotRef> args_slots(args_count);
7594 SlotRef::ComputeSlotMappingForArguments(frame,
7595 inlined_frame_index,
7596 &args_slots);
7597
7598 *total_argc = bound_argc + args_count;
7599 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7600 for (int i = 0; i < args_count; i++) {
7601 Handle<Object> val = args_slots[i].GetValue();
7602 param_data[bound_argc + i] = val.location();
7603 }
7604 return param_data;
7605 } else {
7606 it.AdvanceToArgumentsFrame();
7607 frame = it.frame();
7608 int args_count = frame->ComputeParametersCount();
7609
7610 *total_argc = bound_argc + args_count;
7611 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7612 for (int i = 0; i < args_count; i++) {
7613 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7614 param_data[bound_argc + i] = val.location();
7615 }
7616 return param_data;
7617 }
7618}
7619
7620
7621RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007622 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007623 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007624 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007625 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007626
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007627 // Second argument is either null or an array of bound arguments.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007628 Handle<FixedArray> bound_args;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007629 int bound_argc = 0;
7630 if (!args[1]->IsNull()) {
7631 CONVERT_ARG_CHECKED(JSArray, params, 1);
7632 RUNTIME_ASSERT(params->HasFastElements());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007633 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007634 bound_argc = Smi::cast(params->length())->value();
7635 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007636
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007637 int total_argc = 0;
7638 SmartPointer<Object**> param_data =
7639 GetNonBoundArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007640 for (int i = 0; i < bound_argc; i++) {
7641 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007642 param_data[i] = val.location();
7643 }
7644
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007645 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007646 Handle<Object> result =
7647 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007648 if (exception) {
7649 return Failure::Exception();
7650 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007651
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007652 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007653 return *result;
7654}
7655
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007656
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007657static void TrySettingInlineConstructStub(Isolate* isolate,
7658 Handle<JSFunction> function) {
7659 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007660 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007661 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007662 }
7663 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007664 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00007665 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007666 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007667 function->shared()->set_construct_stub(
7668 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007669 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007670 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007671}
7672
7673
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007674RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007675 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007676 ASSERT(args.length() == 1);
7677
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007678 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007679
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007680 // If the constructor isn't a proper function we throw a type error.
7681 if (!constructor->IsJSFunction()) {
7682 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7683 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007684 isolate->factory()->NewTypeError("not_constructor", arguments);
7685 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007686 }
7687
7688 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007689
7690 // If function should not have prototype, construction is not allowed. In this
7691 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00007692 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007693 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7694 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007695 isolate->factory()->NewTypeError("not_constructor", arguments);
7696 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007697 }
7698
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007699#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007700 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007701 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007702 if (debug->StepInActive()) {
7703 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007704 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007705#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007706
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007707 if (function->has_initial_map()) {
7708 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007709 // The 'Function' function ignores the receiver object when
7710 // called using 'new' and creates a new JSFunction object that
7711 // is returned. The receiver object is only used for error
7712 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007713 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007714 // allocate JSFunctions since it does not properly initialize
7715 // the shared part of the function. Since the receiver is
7716 // ignored anyway, we use the global object as the receiver
7717 // instead of a new JSFunction object. This way, errors are
7718 // reported the same way whether or not 'Function' is called
7719 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007720 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007721 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007722 }
7723
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007724 // The function should be compiled for the optimization hints to be
7725 // available. We cannot use EnsureCompiled because that forces a
7726 // compilation through the shared function info which makes it
7727 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007728 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007729 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007730
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007731 if (!function->has_initial_map() &&
7732 shared->IsInobjectSlackTrackingInProgress()) {
7733 // The tracking is already in progress for another function. We can only
7734 // track one initial_map at a time, so we force the completion before the
7735 // function is called as a constructor for the first time.
7736 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007737 }
7738
7739 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007740 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7741 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007742 // Delay setting the stub if inobject slack tracking is in progress.
7743 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007744 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007745 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007746
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007747 isolate->counters()->constructed_objects()->Increment();
7748 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007749
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007750 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007751}
7752
7753
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007754RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007755 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007756 ASSERT(args.length() == 1);
7757
7758 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7759 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007760 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007761
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007762 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007763}
7764
7765
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007766RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007767 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007768 ASSERT(args.length() == 1);
7769
7770 Handle<JSFunction> function = args.at<JSFunction>(0);
7771#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007772 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007773 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007774 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007775 PrintF("]\n");
7776 }
7777#endif
7778
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007779 // Compile the target function. Here we compile using CompileLazyInLoop in
7780 // order to get the optimized version. This helps code like delta-blue
7781 // that calls performance-critical routines through constructors. A
7782 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
7783 // direct call. Since the in-loop tracking takes place through CallICs
7784 // this means that things called through constructors are never known to
7785 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007786 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007787 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007788 return Failure::Exception();
7789 }
7790
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007791 // All done. Return the compiled code.
7792 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007793 return function->code();
7794}
7795
7796
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007797RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007798 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007799 ASSERT(args.length() == 1);
7800 Handle<JSFunction> function = args.at<JSFunction>(0);
7801 // If the function is not optimizable or debugger is active continue using the
7802 // code from the full compiler.
7803 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007804 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007805 if (FLAG_trace_opt) {
7806 PrintF("[failed to optimize ");
7807 function->PrintName();
7808 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7809 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007810 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007811 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007812 function->ReplaceCode(function->shared()->code());
7813 return function->code();
7814 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007815 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007816 return function->code();
7817 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007818 if (FLAG_trace_opt) {
7819 PrintF("[failed to optimize ");
7820 function->PrintName();
7821 PrintF(": optimized compilation failed]\n");
7822 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007823 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007824 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007825}
7826
7827
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007828RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007829 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007830 ASSERT(args.length() == 1);
7831 RUNTIME_ASSERT(args[0]->IsSmi());
7832 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007833 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007834 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
7835 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007836 int frames = deoptimizer->output_count();
7837
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007838 deoptimizer->MaterializeHeapNumbers();
7839 delete deoptimizer;
7840
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007841 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007842 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007843 for (int i = 0; i < frames - 1; i++) it.Advance();
7844 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007845
7846 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007847 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007848 Handle<Object> arguments;
7849 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007850 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007851 if (arguments.is_null()) {
7852 // FunctionGetArguments can't throw an exception, so cast away the
7853 // doubt with an assert.
7854 arguments = Handle<Object>(
7855 Accessors::FunctionGetArguments(*function,
7856 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007857 ASSERT(*arguments != isolate->heap()->null_value());
7858 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007859 }
7860 frame->SetExpression(i, *arguments);
7861 }
7862 }
7863
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007864 if (type == Deoptimizer::EAGER) {
7865 RUNTIME_ASSERT(function->IsOptimized());
7866 } else {
7867 RUNTIME_ASSERT(!function->IsOptimized());
7868 }
7869
7870 // Avoid doing too much work when running with --always-opt and keep
7871 // the optimized code around.
7872 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007873 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007874 }
7875
7876 // Count the number of optimized activations of the function.
7877 int activations = 0;
7878 while (!it.done()) {
7879 JavaScriptFrame* frame = it.frame();
7880 if (frame->is_optimized() && frame->function() == *function) {
7881 activations++;
7882 }
7883 it.Advance();
7884 }
7885
7886 // TODO(kasperl): For now, we cannot support removing the optimized
7887 // code when we have recursive invocations of the same function.
7888 if (activations == 0) {
7889 if (FLAG_trace_deopt) {
7890 PrintF("[removing optimized code for: ");
7891 function->PrintName();
7892 PrintF("]\n");
7893 }
7894 function->ReplaceCode(function->shared()->code());
7895 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007896 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007897}
7898
7899
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007900RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007901 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007902 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007903 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007904}
7905
7906
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007907RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007908 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007909 ASSERT(args.length() == 1);
7910 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007911 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007912
7913 Deoptimizer::DeoptimizeFunction(*function);
7914
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007915 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007916}
7917
7918
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007919RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
7920#if defined(USE_SIMULATOR)
7921 return isolate->heap()->true_value();
7922#else
7923 return isolate->heap()->false_value();
7924#endif
7925}
7926
7927
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00007928RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
7929 HandleScope scope(isolate);
7930 ASSERT(args.length() == 1);
7931 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7932 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
7933 function->MarkForLazyRecompilation();
7934 return isolate->heap()->undefined_value();
7935}
7936
7937
lrn@chromium.org1c092762011-05-09 09:42:16 +00007938RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
7939 HandleScope scope(isolate);
7940 ASSERT(args.length() == 1);
7941 if (!V8::UseCrankshaft()) {
7942 return Smi::FromInt(4); // 4 == "never".
7943 }
7944 if (FLAG_always_opt) {
7945 return Smi::FromInt(3); // 3 == "always".
7946 }
7947 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7948 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
7949 : Smi::FromInt(2); // 2 == "no".
7950}
7951
7952
7953RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
7954 HandleScope scope(isolate);
7955 ASSERT(args.length() == 1);
7956 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7957 return Smi::FromInt(function->shared()->opt_count());
7958}
7959
7960
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007961RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007962 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007963 ASSERT(args.length() == 1);
7964 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7965
7966 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00007967 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007968
7969 // We have hit a back edge in an unoptimized frame for a function that was
7970 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007971 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007972 // Keep track of whether we've succeeded in optimizing.
7973 bool succeeded = unoptimized->optimizable();
7974 if (succeeded) {
7975 // If we are trying to do OSR when there are already optimized
7976 // activations of the function, it means (a) the function is directly or
7977 // indirectly recursive and (b) an optimized invocation has been
7978 // deoptimized so that we are currently in an unoptimized activation.
7979 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007980 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007981 while (succeeded && !it.done()) {
7982 JavaScriptFrame* frame = it.frame();
7983 succeeded = !frame->is_optimized() || frame->function() != *function;
7984 it.Advance();
7985 }
7986 }
7987
7988 int ast_id = AstNode::kNoNumber;
7989 if (succeeded) {
7990 // The top JS function is this one, the PC is somewhere in the
7991 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007992 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007993 JavaScriptFrame* frame = it.frame();
7994 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007995 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007996 ASSERT(unoptimized->contains(frame->pc()));
7997
7998 // Use linear search of the unoptimized code's stack check table to find
7999 // the AST id matching the PC.
8000 Address start = unoptimized->instruction_start();
8001 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008002 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008003 uint32_t table_length = Memory::uint32_at(table_cursor);
8004 table_cursor += kIntSize;
8005 for (unsigned i = 0; i < table_length; ++i) {
8006 // Table entries are (AST id, pc offset) pairs.
8007 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8008 if (pc_offset == target_pc_offset) {
8009 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8010 break;
8011 }
8012 table_cursor += 2 * kIntSize;
8013 }
8014 ASSERT(ast_id != AstNode::kNoNumber);
8015 if (FLAG_trace_osr) {
8016 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8017 function->PrintName();
8018 PrintF("]\n");
8019 }
8020
8021 // Try to compile the optimized code. A true return value from
8022 // CompileOptimized means that compilation succeeded, not necessarily
8023 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008024 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
8025 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008026 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8027 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008028 if (data->OsrPcOffset()->value() >= 0) {
8029 if (FLAG_trace_osr) {
8030 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008031 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008032 }
8033 ASSERT(data->OsrAstId()->value() == ast_id);
8034 } else {
8035 // We may never generate the desired OSR entry if we emit an
8036 // early deoptimize.
8037 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008038 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008039 } else {
8040 succeeded = false;
8041 }
8042 }
8043
8044 // Revert to the original stack checks in the original unoptimized code.
8045 if (FLAG_trace_osr) {
8046 PrintF("[restoring original stack checks in ");
8047 function->PrintName();
8048 PrintF("]\n");
8049 }
8050 StackCheckStub check_stub;
8051 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008052 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008053 Deoptimizer::RevertStackCheckCode(*unoptimized,
8054 *check_code,
8055 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008056
8057 // Allow OSR only at nesting level zero again.
8058 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8059
8060 // If the optimization attempt succeeded, return the AST id tagged as a
8061 // smi. This tells the builtin that we need to translate the unoptimized
8062 // frame to an optimized one.
8063 if (succeeded) {
8064 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8065 return Smi::FromInt(ast_id);
8066 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008067 if (function->IsMarkedForLazyRecompilation()) {
8068 function->ReplaceCode(function->shared()->code());
8069 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008070 return Smi::FromInt(-1);
8071 }
8072}
8073
8074
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008075RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008076 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008077 ASSERT(args.length() == 1);
8078 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8079 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8080}
8081
8082
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008083RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008084 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008085 ASSERT(args.length() == 1);
8086 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8087 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8088}
8089
8090
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008091RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008092 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008093 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008094
kasper.lund7276f142008-07-30 08:49:36 +00008095 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00008096 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008097 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008098 { MaybeObject* maybe_result =
8099 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008100 if (!maybe_result->ToObject(&result)) return maybe_result;
8101 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008102
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008103 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008104
kasper.lund7276f142008-07-30 08:49:36 +00008105 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008106}
8107
lrn@chromium.org303ada72010-10-27 09:33:13 +00008108
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008109RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8110 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008111 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008112 JSObject* extension_object;
8113 if (args[0]->IsJSObject()) {
8114 extension_object = JSObject::cast(args[0]);
8115 } else {
8116 // Convert the object to a proper JavaScript object.
8117 MaybeObject* maybe_js_object = args[0]->ToObject();
8118 if (!maybe_js_object->To(&extension_object)) {
8119 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8120 HandleScope scope(isolate);
8121 Handle<Object> handle = args.at<Object>(0);
8122 Handle<Object> result =
8123 isolate->factory()->NewTypeError("with_expression",
8124 HandleVector(&handle, 1));
8125 return isolate->Throw(*result);
8126 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008127 return maybe_js_object;
8128 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008129 }
8130 }
8131
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008132 JSFunction* function;
8133 if (args[1]->IsSmi()) {
8134 // A smi sentinel indicates a context nested inside global code rather
8135 // than some function. There is a canonical empty function that can be
8136 // gotten from the global context.
8137 function = isolate->context()->global_context()->closure();
8138 } else {
8139 function = JSFunction::cast(args[1]);
8140 }
8141
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008142 Context* context;
8143 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008144 isolate->heap()->AllocateWithContext(function,
8145 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008146 extension_object);
8147 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008148 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008149 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008150}
8151
8152
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008153RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008154 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008155 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008156 String* name = String::cast(args[0]);
8157 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008158 JSFunction* function;
8159 if (args[2]->IsSmi()) {
8160 // A smi sentinel indicates a context nested inside global code rather
8161 // than some function. There is a canonical empty function that can be
8162 // gotten from the global context.
8163 function = isolate->context()->global_context()->closure();
8164 } else {
8165 function = JSFunction::cast(args[2]);
8166 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008167 Context* context;
8168 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008169 isolate->heap()->AllocateCatchContext(function,
8170 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008171 name,
8172 thrown_object);
8173 if (!maybe_context->To(&context)) return maybe_context;
8174 isolate->set_context(context);
8175 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008176}
8177
8178
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008179RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008180 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008181 ASSERT(args.length() == 2);
8182
8183 CONVERT_ARG_CHECKED(Context, context, 0);
8184 CONVERT_ARG_CHECKED(String, name, 1);
8185
8186 int index;
8187 PropertyAttributes attributes;
8188 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008189 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008190
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008191 // If the slot was not found the result is true.
8192 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008193 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008194 }
8195
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008196 // If the slot was found in a context, it should be DONT_DELETE.
8197 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008198 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008199 }
8200
8201 // The slot was found in a JSObject, either a context extension object,
8202 // the global object, or an arguments object. Try to delete it
8203 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
8204 // which allows deleting all parameters in functions that mention
8205 // 'arguments', we do this even for the case of slots found on an
8206 // arguments object. The slot was found on an arguments object if the
8207 // index is non-negative.
8208 Handle<JSObject> object = Handle<JSObject>::cast(holder);
8209 if (index >= 0) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008210 return object->DeleteElement(index, JSReceiver::NORMAL_DELETION);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008211 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008212 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008213 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008214}
8215
8216
ager@chromium.orga1645e22009-09-09 19:27:10 +00008217// A mechanism to return a pair of Object pointers in registers (if possible).
8218// How this is achieved is calling convention-dependent.
8219// All currently supported x86 compiles uses calling conventions that are cdecl
8220// variants where a 64-bit value is returned in two 32-bit registers
8221// (edx:eax on ia32, r1:r0 on ARM).
8222// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8223// In Win64 calling convention, a struct of two pointers is returned in memory,
8224// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008225#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008226struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008227 MaybeObject* x;
8228 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008229};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008230
lrn@chromium.org303ada72010-10-27 09:33:13 +00008231static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008232 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008233 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8234 // In Win64 they are assigned to a hidden first argument.
8235 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008236}
8237#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008238typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008239static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008240 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008241 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008242}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008243#endif
8244
8245
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008246static inline MaybeObject* Unhole(Heap* heap,
8247 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008248 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008249 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8250 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008251 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008252}
8253
8254
danno@chromium.org40cb8782011-05-25 07:58:50 +00008255static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8256 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008257 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008258 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008259 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008260 JSFunction* context_extension_function =
8261 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008262 // If the holder isn't a context extension object, we just return it
8263 // as the receiver. This allows arguments objects to be used as
8264 // receivers, but only if they are put in the context scope chain
8265 // explicitly via a with-statement.
8266 Object* constructor = holder->map()->constructor();
8267 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008268 // Fall back to using the global object as the implicit receiver if
8269 // the property turns out to be a local variable allocated in a
8270 // context extension object - introduced via eval. Implicit global
8271 // receivers are indicated with the hole value.
8272 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008273}
8274
8275
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008276static ObjectPair LoadContextSlotHelper(Arguments args,
8277 Isolate* isolate,
8278 bool throw_error) {
8279 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008280 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008281
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008282 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008283 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008284 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008285 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008286 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008287
8288 int index;
8289 PropertyAttributes attributes;
8290 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008291 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008292
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008293 // If the index is non-negative, the slot has been found in a local
8294 // variable or a parameter. Read it from the context object or the
8295 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008296 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008297 // If the "property" we were looking for is a local variable or an
8298 // argument in a context, the receiver is the global object; see
8299 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008300 //
8301 // Use the hole as the receiver to signal that the receiver is
8302 // implicit and that the global receiver should be used.
8303 Handle<Object> receiver = isolate->factory()->the_hole_value();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008304 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008305 ? Context::cast(*holder)->get(index)
8306 : JSObject::cast(*holder)->GetElement(index);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008307 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008308 }
8309
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008310 // If the holder is found, we read the property from it.
8311 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008312 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008313 JSObject* object = JSObject::cast(*holder);
danno@chromium.org40cb8782011-05-25 07:58:50 +00008314 Object* receiver;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008315 if (object->IsGlobalObject()) {
8316 receiver = GlobalObject::cast(object)->global_receiver();
8317 } else if (context->is_exception_holder(*holder)) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008318 // Use the hole as the receiver to signal that the receiver is
8319 // implicit and that the global receiver should be used.
8320 receiver = isolate->heap()->the_hole_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008321 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008322 receiver = ComputeReceiverForNonGlobal(isolate, object);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008323 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008324
8325 // GetProperty below can cause GC.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008326 Handle<Object> receiver_handle(receiver);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008327
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008328 // No need to unhole the value here. This is taken care of by the
8329 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008330 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008331 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008332 }
8333
8334 if (throw_error) {
8335 // The property doesn't exist - throw exception.
8336 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008337 isolate->factory()->NewReferenceError("not_defined",
8338 HandleVector(&name, 1));
8339 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008340 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008341 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008342 return MakePair(isolate->heap()->undefined_value(),
8343 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008344 }
8345}
8346
8347
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008348RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008349 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008350}
8351
8352
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008353RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008354 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008355}
8356
8357
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008358RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008359 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008360 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008361
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008362 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008363 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008364 CONVERT_ARG_CHECKED(String, name, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008365 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008366 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
8367 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008368 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008369
8370 int index;
8371 PropertyAttributes attributes;
8372 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008373 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008374
8375 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008376 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008377 // Ignore if read_only variable.
8378 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008379 // Context is a fixed array and set cannot fail.
8380 Context::cast(*holder)->set(index, *value);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008381 } else if (strict_mode == kStrictMode) {
8382 // Setting read only property in strict mode.
8383 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008384 isolate->factory()->NewTypeError("strict_cannot_assign",
8385 HandleVector(&name, 1));
8386 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008387 }
8388 } else {
8389 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008390 Handle<Object> result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008391 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008392 if (result.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008393 ASSERT(isolate->has_pending_exception());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008394 return Failure::Exception();
8395 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008396 }
8397 return *value;
8398 }
8399
8400 // Slow case: The property is not in a FixedArray context.
8401 // It is either in an JSObject extension context or it was not found.
8402 Handle<JSObject> context_ext;
8403
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008404 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008405 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008406 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008407 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008408 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008409 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008410
8411 if (strict_mode == kStrictMode) {
8412 // Throw in strict mode (assignment to undefined variable).
8413 Handle<Object> error =
8414 isolate->factory()->NewReferenceError(
8415 "not_defined", HandleVector(&name, 1));
8416 return isolate->Throw(*error);
8417 }
8418 // In non-strict mode, the property is stored in the global context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008419 attributes = NONE;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008420 context_ext = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008421 }
8422
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008423 // Set the property, but ignore if read_only variable on the context
8424 // extension object itself.
8425 if ((attributes & READ_ONLY) == 0 ||
8426 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008427 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008428 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008429 SetProperty(context_ext, name, value, NONE, strict_mode));
8430 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008431 // Setting read only property in strict mode.
8432 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008433 isolate->factory()->NewTypeError(
8434 "strict_cannot_assign", HandleVector(&name, 1));
8435 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008436 }
8437 return *value;
8438}
8439
8440
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008441RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008442 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008443 ASSERT(args.length() == 1);
8444
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008445 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008446}
8447
8448
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008449RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008450 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008451 ASSERT(args.length() == 1);
8452
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008453 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008454}
8455
8456
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008457RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008458 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008459 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008460}
8461
8462
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008463RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008464 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008465 ASSERT(args.length() == 1);
8466
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008467 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008468 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008469 isolate->factory()->NewReferenceError("not_defined",
8470 HandleVector(&name, 1));
8471 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008472}
8473
8474
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008475RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008476 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008477
8478 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008479 if (isolate->stack_guard()->IsStackOverflow()) {
8480 NoHandleAllocation na;
8481 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008482 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008483
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008484 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008485}
8486
8487
8488// NOTE: These PrintXXX functions are defined for all builds (not just
8489// DEBUG builds) because we may want to be able to trace function
8490// calls in all modes.
8491static void PrintString(String* str) {
8492 // not uncommon to have empty strings
8493 if (str->length() > 0) {
8494 SmartPointer<char> s =
8495 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
8496 PrintF("%s", *s);
8497 }
8498}
8499
8500
8501static void PrintObject(Object* obj) {
8502 if (obj->IsSmi()) {
8503 PrintF("%d", Smi::cast(obj)->value());
8504 } else if (obj->IsString() || obj->IsSymbol()) {
8505 PrintString(String::cast(obj));
8506 } else if (obj->IsNumber()) {
8507 PrintF("%g", obj->Number());
8508 } else if (obj->IsFailure()) {
8509 PrintF("<failure>");
8510 } else if (obj->IsUndefined()) {
8511 PrintF("<undefined>");
8512 } else if (obj->IsNull()) {
8513 PrintF("<null>");
8514 } else if (obj->IsTrue()) {
8515 PrintF("<true>");
8516 } else if (obj->IsFalse()) {
8517 PrintF("<false>");
8518 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008519 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008520 }
8521}
8522
8523
8524static int StackSize() {
8525 int n = 0;
8526 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8527 return n;
8528}
8529
8530
8531static void PrintTransition(Object* result) {
8532 // indentation
8533 { const int nmax = 80;
8534 int n = StackSize();
8535 if (n <= nmax)
8536 PrintF("%4d:%*s", n, n, "");
8537 else
8538 PrintF("%4d:%*s", n, nmax, "...");
8539 }
8540
8541 if (result == NULL) {
8542 // constructor calls
8543 JavaScriptFrameIterator it;
8544 JavaScriptFrame* frame = it.frame();
8545 if (frame->IsConstructor()) PrintF("new ");
8546 // function name
8547 Object* fun = frame->function();
8548 if (fun->IsJSFunction()) {
8549 PrintObject(JSFunction::cast(fun)->shared()->name());
8550 } else {
8551 PrintObject(fun);
8552 }
8553 // function arguments
8554 // (we are intentionally only printing the actually
8555 // supplied parameters, not all parameters required)
8556 PrintF("(this=");
8557 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008558 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008559 for (int i = 0; i < length; i++) {
8560 PrintF(", ");
8561 PrintObject(frame->GetParameter(i));
8562 }
8563 PrintF(") {\n");
8564
8565 } else {
8566 // function result
8567 PrintF("} -> ");
8568 PrintObject(result);
8569 PrintF("\n");
8570 }
8571}
8572
8573
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008574RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008575 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008576 NoHandleAllocation ha;
8577 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008578 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008579}
8580
8581
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008582RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008583 NoHandleAllocation ha;
8584 PrintTransition(args[0]);
8585 return args[0]; // return TOS
8586}
8587
8588
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008589RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008590 NoHandleAllocation ha;
8591 ASSERT(args.length() == 1);
8592
8593#ifdef DEBUG
8594 if (args[0]->IsString()) {
8595 // If we have a string, assume it's a code "marker"
8596 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008597 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008598 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008599 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8600 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008601 } else {
8602 PrintF("DebugPrint: ");
8603 }
8604 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008605 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008606 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008607 HeapObject::cast(args[0])->map()->Print();
8608 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008609#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008610 // ShortPrint is available in release mode. Print is not.
8611 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008612#endif
8613 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00008614 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008615
8616 return args[0]; // return TOS
8617}
8618
8619
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008620RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008621 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008622 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008623 isolate->PrintStack();
8624 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008625}
8626
8627
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008628RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008629 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008630 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008631
8632 // According to ECMA-262, section 15.9.1, page 117, the precision of
8633 // the number in a Date object representing a particular instant in
8634 // time is milliseconds. Therefore, we floor the result of getting
8635 // the OS time.
8636 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008637 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008638}
8639
8640
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008641RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008642 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008643 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008644
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008645 CONVERT_ARG_CHECKED(String, str, 0);
8646 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008647
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008648 CONVERT_ARG_CHECKED(JSArray, output, 1);
8649 RUNTIME_ASSERT(output->HasFastElements());
8650
8651 AssertNoAllocation no_allocation;
8652
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008653 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008654 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
8655 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008656 if (str->IsAsciiRepresentation()) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008657 result = DateParser::Parse(str->ToAsciiVector(),
8658 output_array,
8659 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008660 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008661 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008662 result = DateParser::Parse(str->ToUC16Vector(),
8663 output_array,
8664 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008665 }
8666
8667 if (result) {
8668 return *output;
8669 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008670 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008671 }
8672}
8673
8674
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008675RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008676 NoHandleAllocation ha;
8677 ASSERT(args.length() == 1);
8678
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008679 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00008680 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008681 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008682}
8683
8684
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008685RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008686 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008687 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008688
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008689 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008690}
8691
8692
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008693RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008694 NoHandleAllocation ha;
8695 ASSERT(args.length() == 1);
8696
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008697 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008698 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008699}
8700
8701
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008702RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008703 ASSERT(args.length() == 1);
8704 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008705 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008706 return JSGlobalObject::cast(global)->global_receiver();
8707}
8708
8709
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008710RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008711 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008712 ASSERT_EQ(1, args.length());
8713 CONVERT_ARG_CHECKED(String, source, 0);
8714
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00008715 source = Handle<String>(source->TryFlattenGetString());
8716 // Optimized fast case where we only have ascii characters.
8717 Handle<Object> result;
8718 if (source->IsSeqAsciiString()) {
8719 result = JsonParser<true>::Parse(source);
8720 } else {
8721 result = JsonParser<false>::Parse(source);
8722 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008723 if (result.is_null()) {
8724 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008725 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008726 return Failure::Exception();
8727 }
8728 return *result;
8729}
8730
8731
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008732bool CodeGenerationFromStringsAllowed(Isolate* isolate,
8733 Handle<Context> context) {
8734 if (context->allow_code_gen_from_strings()->IsFalse()) {
8735 // Check with callback if set.
8736 AllowCodeGenerationFromStringsCallback callback =
8737 isolate->allow_code_gen_callback();
8738 if (callback == NULL) {
8739 // No callback set and code generation disallowed.
8740 return false;
8741 } else {
8742 // Callback set. Let it decide if code generation is allowed.
8743 VMState state(isolate, EXTERNAL);
8744 return callback(v8::Utils::ToLocal(context));
8745 }
8746 }
8747 return true;
8748}
8749
8750
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008751RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008752 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008753 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008754 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008755
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008756 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008757 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008758
8759 // Check if global context allows code generation from
8760 // strings. Throw an exception if it doesn't.
8761 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
8762 return isolate->Throw(*isolate->factory()->NewError(
8763 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8764 }
8765
8766 // Compile source string in the global context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008767 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
8768 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008769 true,
8770 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008771 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008772 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008773 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8774 context,
8775 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008776 return *fun;
8777}
8778
8779
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008780static ObjectPair CompileGlobalEval(Isolate* isolate,
8781 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008782 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008783 StrictModeFlag strict_mode) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008784 Handle<Context> context = Handle<Context>(isolate->context());
8785 Handle<Context> global_context = Handle<Context>(context->global_context());
8786
8787 // Check if global context allows code generation from
8788 // strings. Throw an exception if it doesn't.
8789 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
8790 isolate->Throw(*isolate->factory()->NewError(
8791 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8792 return MakePair(Failure::Exception(), NULL);
8793 }
8794
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008795 // Deal with a normal eval call with a string argument. Compile it
8796 // and return the compiled function bound in the local context.
8797 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
8798 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008799 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008800 context->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008801 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008802 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008803 Handle<JSFunction> compiled =
8804 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008805 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008806 return MakePair(*compiled, *receiver);
8807}
8808
8809
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008810RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008811 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008812
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008813 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008814 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008815 Handle<Object> receiver; // Will be overwritten.
8816
8817 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008818 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008819#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008820 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008821 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008822 StackFrameLocator locator;
8823 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008824 ASSERT(Context::cast(frame->context()) == *context);
8825#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008826
8827 // Find where the 'eval' symbol is bound. It is unaliased only if
8828 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008829 int index = -1;
8830 PropertyAttributes attributes = ABSENT;
8831 while (true) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008832 receiver = context->Lookup(isolate->factory()->eval_symbol(),
8833 FOLLOW_PROTOTYPE_CHAIN,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008834 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008835 // Stop search when eval is found or when the global context is
8836 // reached.
8837 if (attributes != ABSENT || context->IsGlobalContext()) break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008838 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008839 }
8840
iposva@chromium.org245aa852009-02-10 00:49:54 +00008841 // If eval could not be resolved, it has been deleted and we need to
8842 // throw a reference error.
8843 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008844 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00008845 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008846 isolate->factory()->NewReferenceError("not_defined",
8847 HandleVector(&name, 1));
8848 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008849 }
8850
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008851 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008852 // 'eval' is not bound in the global context. Just call the function
8853 // with the given arguments. This is not necessarily the global eval.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00008854 if (receiver->IsContext() || receiver->IsJSContextExtensionObject()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008855 receiver = isolate->factory()->the_hole_value();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008856 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008857 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008858 }
8859
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008860 // 'eval' is bound in the global context, but it may have been overwritten.
8861 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008862 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008863 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008864 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008865 }
8866
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008867 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008868 return CompileGlobalEval(isolate,
8869 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008870 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008871 static_cast<StrictModeFlag>(args.smi_at(3)));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008872}
8873
8874
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008875RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008876 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008877
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008878 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008879 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008880
8881 // 'eval' is bound in the global context, but it may have been overwritten.
8882 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008883 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008884 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008885 return MakePair(*callee, isolate->heap()->the_hole_value());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008886 }
8887
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008888 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008889 return CompileGlobalEval(isolate,
8890 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008891 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008892 static_cast<StrictModeFlag>(args.smi_at(3)));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008893}
8894
8895
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008896RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008897 // This utility adjusts the property attributes for newly created Function
8898 // object ("new Function(...)") by changing the map.
8899 // All it does is changing the prototype property to enumerable
8900 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008901 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008902 ASSERT(args.length() == 1);
8903 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008904
8905 Handle<Map> map = func->shared()->strict_mode()
8906 ? isolate->strict_mode_function_instance_map()
8907 : isolate->function_instance_map();
8908
8909 ASSERT(func->map()->instance_type() == map->instance_type());
8910 ASSERT(func->map()->instance_size() == map->instance_size());
8911 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008912 return *func;
8913}
8914
8915
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008916RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008917 // Allocate a block of memory in NewSpace (filled with a filler).
8918 // Use as fallback for allocation in generated code when NewSpace
8919 // is full.
8920 ASSERT(args.length() == 1);
8921 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
8922 int size = size_smi->value();
8923 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
8924 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008925 Heap* heap = isolate->heap();
8926 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008927 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008928 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008929 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008930 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008931 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008932 }
8933 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008934 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008935}
8936
8937
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008938// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008939// array. Returns true if the element was pushed on the stack and
8940// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008941RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008942 ASSERT(args.length() == 2);
8943 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008944 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008945 RUNTIME_ASSERT(array->HasFastElements());
8946 int length = Smi::cast(array->length())->value();
8947 FixedArray* elements = FixedArray::cast(array->elements());
8948 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008949 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008950 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008951 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008952 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008953 { MaybeObject* maybe_obj =
8954 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008955 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8956 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008957 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008958}
8959
8960
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008961/**
8962 * A simple visitor visits every element of Array's.
8963 * The backend storage can be a fixed array for fast elements case,
8964 * or a dictionary for sparse array. Since Dictionary is a subtype
8965 * of FixedArray, the class can be used by both fast and slow cases.
8966 * The second parameter of the constructor, fast_elements, specifies
8967 * whether the storage is a FixedArray or Dictionary.
8968 *
8969 * An index limit is used to deal with the situation that a result array
8970 * length overflows 32-bit non-negative integer.
8971 */
8972class ArrayConcatVisitor {
8973 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008974 ArrayConcatVisitor(Isolate* isolate,
8975 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008976 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008977 isolate_(isolate),
8978 storage_(Handle<FixedArray>::cast(
8979 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008980 index_offset_(0u),
8981 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008982
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008983 ~ArrayConcatVisitor() {
8984 clear_storage();
8985 }
8986
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008987 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008988 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008989 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008990
8991 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008992 if (index < static_cast<uint32_t>(storage_->length())) {
8993 storage_->set(index, *elm);
8994 return;
8995 }
8996 // Our initial estimate of length was foiled, possibly by
8997 // getters on the arrays increasing the length of later arrays
8998 // during iteration.
8999 // This shouldn't happen in anything but pathological cases.
9000 SetDictionaryMode(index);
9001 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009002 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009003 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009004 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009005 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009006 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009007 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009008 // Dictionary needed to grow.
9009 clear_storage();
9010 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009011 }
9012}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009013
9014 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009015 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9016 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009017 } else {
9018 index_offset_ += delta;
9019 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009020 }
9021
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009022 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009023 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009024 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009025 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009026 Handle<Map> map;
9027 if (fast_elements_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009028 map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009029 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009030 map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009031 }
9032 array->set_map(*map);
9033 array->set_length(*length);
9034 array->set_elements(*storage_);
9035 return array;
9036 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009037
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009038 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009039 // Convert storage to dictionary mode.
9040 void SetDictionaryMode(uint32_t index) {
9041 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009042 Handle<FixedArray> current_storage(*storage_);
9043 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009044 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009045 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9046 for (uint32_t i = 0; i < current_length; i++) {
9047 HandleScope loop_scope;
9048 Handle<Object> element(current_storage->get(i));
9049 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009050 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009051 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009052 if (!new_storage.is_identical_to(slow_storage)) {
9053 slow_storage = loop_scope.CloseAndEscape(new_storage);
9054 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009055 }
9056 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009057 clear_storage();
9058 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009059 fast_elements_ = false;
9060 }
9061
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009062 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009063 isolate_->global_handles()->Destroy(
9064 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009065 }
9066
9067 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009068 storage_ = Handle<FixedArray>::cast(
9069 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009070 }
9071
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009072 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009073 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009074 // Index after last seen index. Always less than or equal to
9075 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009076 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009077 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009078};
9079
9080
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009081static uint32_t EstimateElementCount(Handle<JSArray> array) {
9082 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9083 int element_count = 0;
9084 switch (array->GetElementsKind()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009085 case JSObject::FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009086 // Fast elements can't have lengths that are not representable by
9087 // a 32-bit signed integer.
9088 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9089 int fast_length = static_cast<int>(length);
9090 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9091 for (int i = 0; i < fast_length; i++) {
9092 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009093 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009094 break;
9095 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009096 case JSObject::DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009097 Handle<NumberDictionary> dictionary(
9098 NumberDictionary::cast(array->elements()));
9099 int capacity = dictionary->Capacity();
9100 for (int i = 0; i < capacity; i++) {
9101 Handle<Object> key(dictionary->KeyAt(i));
9102 if (dictionary->IsKey(*key)) {
9103 element_count++;
9104 }
9105 }
9106 break;
9107 }
9108 default:
9109 // External arrays are always dense.
9110 return length;
9111 }
9112 // As an estimate, we assume that the prototype doesn't contain any
9113 // inherited elements.
9114 return element_count;
9115}
9116
9117
9118
9119template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009120static void IterateExternalArrayElements(Isolate* isolate,
9121 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009122 bool elements_are_ints,
9123 bool elements_are_guaranteed_smis,
9124 ArrayConcatVisitor* visitor) {
9125 Handle<ExternalArrayClass> array(
9126 ExternalArrayClass::cast(receiver->elements()));
9127 uint32_t len = static_cast<uint32_t>(array->length());
9128
9129 ASSERT(visitor != NULL);
9130 if (elements_are_ints) {
9131 if (elements_are_guaranteed_smis) {
9132 for (uint32_t j = 0; j < len; j++) {
9133 HandleScope loop_scope;
9134 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
9135 visitor->visit(j, e);
9136 }
9137 } else {
9138 for (uint32_t j = 0; j < len; j++) {
9139 HandleScope loop_scope;
9140 int64_t val = static_cast<int64_t>(array->get(j));
9141 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9142 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9143 visitor->visit(j, e);
9144 } else {
9145 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009146 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009147 visitor->visit(j, e);
9148 }
9149 }
9150 }
9151 } else {
9152 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009153 HandleScope loop_scope(isolate);
9154 Handle<Object> e = isolate->factory()->NewNumber(array->get(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009155 visitor->visit(j, e);
9156 }
9157 }
9158}
9159
9160
9161// Used for sorting indices in a List<uint32_t>.
9162static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9163 uint32_t a = *ap;
9164 uint32_t b = *bp;
9165 return (a == b) ? 0 : (a < b) ? -1 : 1;
9166}
9167
9168
9169static void CollectElementIndices(Handle<JSObject> object,
9170 uint32_t range,
9171 List<uint32_t>* indices) {
9172 JSObject::ElementsKind kind = object->GetElementsKind();
9173 switch (kind) {
9174 case JSObject::FAST_ELEMENTS: {
9175 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9176 uint32_t length = static_cast<uint32_t>(elements->length());
9177 if (range < length) length = range;
9178 for (uint32_t i = 0; i < length; i++) {
9179 if (!elements->get(i)->IsTheHole()) {
9180 indices->Add(i);
9181 }
9182 }
9183 break;
9184 }
9185 case JSObject::DICTIONARY_ELEMENTS: {
9186 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009187 uint32_t capacity = dict->Capacity();
9188 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009189 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009190 Handle<Object> k(dict->KeyAt(j));
9191 if (dict->IsKey(*k)) {
9192 ASSERT(k->IsNumber());
9193 uint32_t index = static_cast<uint32_t>(k->Number());
9194 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009195 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009196 }
9197 }
9198 }
9199 break;
9200 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009201 default: {
9202 int dense_elements_length;
9203 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009204 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009205 dense_elements_length =
9206 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009207 break;
9208 }
9209 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009210 dense_elements_length =
9211 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009212 break;
9213 }
9214 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009215 dense_elements_length =
9216 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009217 break;
9218 }
9219 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009220 dense_elements_length =
9221 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009222 break;
9223 }
9224 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009225 dense_elements_length =
9226 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009227 break;
9228 }
9229 case JSObject::EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009230 dense_elements_length =
9231 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009232 break;
9233 }
9234 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009235 dense_elements_length =
9236 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009237 break;
9238 }
9239 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009240 dense_elements_length =
9241 ExternalFloatArray::cast(object->elements())->length();
9242 break;
9243 }
9244 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9245 dense_elements_length =
9246 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009247 break;
9248 }
9249 default:
9250 UNREACHABLE();
9251 dense_elements_length = 0;
9252 break;
9253 }
9254 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9255 if (range <= length) {
9256 length = range;
9257 // We will add all indices, so we might as well clear it first
9258 // and avoid duplicates.
9259 indices->Clear();
9260 }
9261 for (uint32_t i = 0; i < length; i++) {
9262 indices->Add(i);
9263 }
9264 if (length == range) return; // All indices accounted for already.
9265 break;
9266 }
9267 }
9268
9269 Handle<Object> prototype(object->GetPrototype());
9270 if (prototype->IsJSObject()) {
9271 // The prototype will usually have no inherited element indices,
9272 // but we have to check.
9273 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9274 }
9275}
9276
9277
9278/**
9279 * A helper function that visits elements of a JSArray in numerical
9280 * order.
9281 *
9282 * The visitor argument called for each existing element in the array
9283 * with the element index and the element's value.
9284 * Afterwards it increments the base-index of the visitor by the array
9285 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009286 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009287 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009288static bool IterateElements(Isolate* isolate,
9289 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009290 ArrayConcatVisitor* visitor) {
9291 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9292 switch (receiver->GetElementsKind()) {
9293 case JSObject::FAST_ELEMENTS: {
9294 // Run through the elements FixedArray and use HasElement and GetElement
9295 // to check the prototype for missing elements.
9296 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9297 int fast_length = static_cast<int>(length);
9298 ASSERT(fast_length <= elements->length());
9299 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009300 HandleScope loop_scope(isolate);
9301 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009302 if (!element_value->IsTheHole()) {
9303 visitor->visit(j, element_value);
9304 } else if (receiver->HasElement(j)) {
9305 // Call GetElement on receiver, not its prototype, or getters won't
9306 // have the correct receiver.
9307 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009308 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009309 visitor->visit(j, element_value);
9310 }
9311 }
9312 break;
9313 }
9314 case JSObject::DICTIONARY_ELEMENTS: {
9315 Handle<NumberDictionary> dict(receiver->element_dictionary());
9316 List<uint32_t> indices(dict->Capacity() / 2);
9317 // Collect all indices in the object and the prototypes less
9318 // than length. This might introduce duplicates in the indices list.
9319 CollectElementIndices(receiver, length, &indices);
9320 indices.Sort(&compareUInt32);
9321 int j = 0;
9322 int n = indices.length();
9323 while (j < n) {
9324 HandleScope loop_scope;
9325 uint32_t index = indices[j];
9326 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009327 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009328 visitor->visit(index, element);
9329 // Skip to next different index (i.e., omit duplicates).
9330 do {
9331 j++;
9332 } while (j < n && indices[j] == index);
9333 }
9334 break;
9335 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009336 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
9337 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9338 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009339 for (uint32_t j = 0; j < length; j++) {
9340 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
9341 visitor->visit(j, e);
9342 }
9343 break;
9344 }
9345 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
9346 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009347 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009348 break;
9349 }
9350 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
9351 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009352 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009353 break;
9354 }
9355 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
9356 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009357 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009358 break;
9359 }
9360 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
9361 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009362 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009363 break;
9364 }
9365 case JSObject::EXTERNAL_INT_ELEMENTS: {
9366 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009367 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009368 break;
9369 }
9370 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
9371 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009372 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009373 break;
9374 }
9375 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
9376 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009377 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009378 break;
9379 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009380 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9381 IterateExternalArrayElements<ExternalDoubleArray, double>(
9382 isolate, receiver, false, false, visitor);
9383 break;
9384 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009385 default:
9386 UNREACHABLE();
9387 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009388 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009389 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009390 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009391}
9392
9393
9394/**
9395 * Array::concat implementation.
9396 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009397 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009398 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009399 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009400RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009401 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009402 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009403
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009404 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
9405 int argument_count = static_cast<int>(arguments->length()->Number());
9406 RUNTIME_ASSERT(arguments->HasFastElements());
9407 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009408
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009409 // Pass 1: estimate the length and number of elements of the result.
9410 // The actual length can be larger if any of the arguments have getters
9411 // that mutate other arguments (but will otherwise be precise).
9412 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009413
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009414 uint32_t estimate_result_length = 0;
9415 uint32_t estimate_nof_elements = 0;
9416 {
9417 for (int i = 0; i < argument_count; i++) {
9418 HandleScope loop_scope;
9419 Handle<Object> obj(elements->get(i));
9420 uint32_t length_estimate;
9421 uint32_t element_estimate;
9422 if (obj->IsJSArray()) {
9423 Handle<JSArray> array(Handle<JSArray>::cast(obj));
9424 length_estimate =
9425 static_cast<uint32_t>(array->length()->Number());
9426 element_estimate =
9427 EstimateElementCount(array);
9428 } else {
9429 length_estimate = 1;
9430 element_estimate = 1;
9431 }
9432 // Avoid overflows by capping at kMaxElementCount.
9433 if (JSObject::kMaxElementCount - estimate_result_length <
9434 length_estimate) {
9435 estimate_result_length = JSObject::kMaxElementCount;
9436 } else {
9437 estimate_result_length += length_estimate;
9438 }
9439 if (JSObject::kMaxElementCount - estimate_nof_elements <
9440 element_estimate) {
9441 estimate_nof_elements = JSObject::kMaxElementCount;
9442 } else {
9443 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009444 }
9445 }
9446 }
9447
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009448 // If estimated number of elements is more than half of length, a
9449 // fixed array (fast case) is more time and space-efficient than a
9450 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009451 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009452
9453 Handle<FixedArray> storage;
9454 if (fast_case) {
9455 // The backing storage array must have non-existing elements to
9456 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009457 storage = isolate->factory()->NewFixedArrayWithHoles(
9458 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009459 } else {
9460 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9461 uint32_t at_least_space_for = estimate_nof_elements +
9462 (estimate_nof_elements >> 2);
9463 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009464 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009465 }
9466
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009467 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009468
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009469 for (int i = 0; i < argument_count; i++) {
9470 Handle<Object> obj(elements->get(i));
9471 if (obj->IsJSArray()) {
9472 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009473 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009474 return Failure::Exception();
9475 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009476 } else {
9477 visitor.visit(0, obj);
9478 visitor.increase_index_offset(1);
9479 }
9480 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009481
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009482 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009483}
9484
9485
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009486// This will not allocate (flatten the string), but it may run
9487// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009488RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009489 NoHandleAllocation ha;
9490 ASSERT(args.length() == 1);
9491
9492 CONVERT_CHECKED(String, string, args[0]);
9493 StringInputBuffer buffer(string);
9494 while (buffer.has_more()) {
9495 uint16_t character = buffer.GetNext();
9496 PrintF("%c", character);
9497 }
9498 return string;
9499}
9500
ager@chromium.org5ec48922009-05-05 07:25:34 +00009501// Moves all own elements of an object, that are below a limit, to positions
9502// starting at zero. All undefined values are placed after non-undefined values,
9503// and are followed by non-existing element. Does not change the length
9504// property.
9505// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009506RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009507 ASSERT(args.length() == 2);
9508 CONVERT_CHECKED(JSObject, object, args[0]);
9509 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9510 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009511}
9512
9513
9514// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009515RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009516 ASSERT(args.length() == 2);
9517 CONVERT_CHECKED(JSArray, from, args[0]);
9518 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009519 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009520 MaybeObject* maybe_new_map;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009521 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9522 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009523 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009524 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009525 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009526 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009527 Object* new_map;
9528 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009529 to->set_map(Map::cast(new_map));
9530 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009531 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009532 Object* obj;
9533 { MaybeObject* maybe_obj = from->ResetElements();
9534 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9535 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009536 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009537 return to;
9538}
9539
9540
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009541// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009542RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009543 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009544 CONVERT_CHECKED(JSObject, object, args[0]);
9545 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009546 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009547 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009548 } else if (object->IsJSArray()) {
9549 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009550 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009551 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009552 }
9553}
9554
9555
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009556RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009557 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009558
9559 ASSERT_EQ(3, args.length());
9560
ager@chromium.orgac091b72010-05-05 07:34:42 +00009561 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009562 Handle<Object> key1 = args.at<Object>(1);
9563 Handle<Object> key2 = args.at<Object>(2);
9564
9565 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009566 if (!key1->ToArrayIndex(&index1)
9567 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009568 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009569 }
9570
ager@chromium.orgac091b72010-05-05 07:34:42 +00009571 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
9572 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009573 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009574 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009575 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009576
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009577 RETURN_IF_EMPTY_HANDLE(isolate,
9578 SetElement(jsobject, index1, tmp2, kStrictMode));
9579 RETURN_IF_EMPTY_HANDLE(isolate,
9580 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00009581
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009582 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009583}
9584
9585
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009586// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009587// might have elements. Can either return keys (positive integers) or
9588// intervals (pair of a negative integer (-start-1) followed by a
9589// positive (length)) or undefined values.
9590// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009591RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009592 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009593 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009594 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009595 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009596 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009597 // Create an array and get all the keys into it, then remove all the
9598 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009599 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009600 int keys_length = keys->length();
9601 for (int i = 0; i < keys_length; i++) {
9602 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009603 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009604 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009605 // Zap invalid keys.
9606 keys->set_undefined(i);
9607 }
9608 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009609 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009610 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009611 ASSERT(array->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009612 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009613 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009614 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009615 uint32_t actual_length =
9616 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009617 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009618 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009619 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009620 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009621 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009622 }
9623}
9624
9625
9626// DefineAccessor takes an optional final argument which is the
9627// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
9628// to the way accessors are implemented, it is set for both the getter
9629// and setter on the first call to DefineAccessor and ignored on
9630// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009631RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009632 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
9633 // Compute attributes.
9634 PropertyAttributes attributes = NONE;
9635 if (args.length() == 5) {
9636 CONVERT_CHECKED(Smi, attrs, args[4]);
9637 int value = attrs->value();
9638 // Only attribute bits should be set.
9639 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
9640 attributes = static_cast<PropertyAttributes>(value);
9641 }
9642
9643 CONVERT_CHECKED(JSObject, obj, args[0]);
9644 CONVERT_CHECKED(String, name, args[1]);
9645 CONVERT_CHECKED(Smi, flag, args[2]);
9646 CONVERT_CHECKED(JSFunction, fun, args[3]);
9647 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
9648}
9649
9650
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009651RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009652 ASSERT(args.length() == 3);
9653 CONVERT_CHECKED(JSObject, obj, args[0]);
9654 CONVERT_CHECKED(String, name, args[1]);
9655 CONVERT_CHECKED(Smi, flag, args[2]);
9656 return obj->LookupAccessor(name, flag->value() == 0);
9657}
9658
9659
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009660#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009661RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009662 ASSERT(args.length() == 0);
9663 return Execution::DebugBreakHelper();
9664}
9665
9666
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009667// Helper functions for wrapping and unwrapping stack frame ids.
9668static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009669 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009670 return Smi::FromInt(id >> 2);
9671}
9672
9673
9674static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
9675 return static_cast<StackFrame::Id>(wrapped->value() << 2);
9676}
9677
9678
9679// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00009680// args[0]: debug event listener function to set or null or undefined for
9681// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009682// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009683RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009684 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009685 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
9686 args[0]->IsUndefined() ||
9687 args[0]->IsNull());
9688 Handle<Object> callback = args.at<Object>(0);
9689 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009690 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009691
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009692 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009693}
9694
9695
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009696RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +00009697 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009698 isolate->stack_guard()->DebugBreak();
9699 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009700}
9701
9702
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009703static MaybeObject* DebugLookupResultValue(Heap* heap,
9704 Object* receiver,
9705 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009706 LookupResult* result,
9707 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009708 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009709 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009710 case NORMAL:
9711 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009712 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009713 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009714 }
9715 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009716 case FIELD:
9717 value =
9718 JSObject::cast(
9719 result->holder())->FastPropertyAt(result->GetFieldIndex());
9720 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009721 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009722 }
9723 return value;
9724 case CONSTANT_FUNCTION:
9725 return result->GetConstantFunction();
9726 case CALLBACKS: {
9727 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00009728 if (structure->IsForeign() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009729 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009730 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009731 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009732 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009733 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009734 maybe_value = heap->isolate()->pending_exception();
9735 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009736 if (caught_exception != NULL) {
9737 *caught_exception = true;
9738 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009739 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009740 }
9741 return value;
9742 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009743 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009744 }
9745 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009746 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009747 case MAP_TRANSITION:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009748 case EXTERNAL_ARRAY_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009749 case CONSTANT_TRANSITION:
9750 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009751 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009752 default:
9753 UNREACHABLE();
9754 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009755 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009756 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009757}
9758
9759
ager@chromium.org32912102009-01-16 10:38:43 +00009760// Get debugger related details for an object property.
9761// args[0]: object holding property
9762// args[1]: name of the property
9763//
9764// The array returned contains the following information:
9765// 0: Property value
9766// 1: Property details
9767// 2: Property value is exception
9768// 3: Getter function if defined
9769// 4: Setter function if defined
9770// Items 2-4 are only filled if the property has either a getter or a setter
9771// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009772RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009773 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009774
9775 ASSERT(args.length() == 2);
9776
9777 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9778 CONVERT_ARG_CHECKED(String, name, 1);
9779
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009780 // Make sure to set the current context to the context before the debugger was
9781 // entered (if the debugger is entered). The reason for switching context here
9782 // is that for some property lookups (accessors and interceptors) callbacks
9783 // into the embedding application can occour, and the embedding application
9784 // could have the assumption that its own global context is the current
9785 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009786 SaveContext save(isolate);
9787 if (isolate->debug()->InDebugger()) {
9788 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009789 }
9790
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009791 // Skip the global proxy as it has no properties and always delegates to the
9792 // real global object.
9793 if (obj->IsJSGlobalProxy()) {
9794 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
9795 }
9796
9797
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009798 // Check if the name is trivially convertible to an index and get the element
9799 // if so.
9800 uint32_t index;
9801 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009802 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009803 Object* element_or_char;
9804 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009805 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009806 if (!maybe_element_or_char->ToObject(&element_or_char)) {
9807 return maybe_element_or_char;
9808 }
9809 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009810 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009811 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009812 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009813 }
9814
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009815 // Find the number of objects making up this.
9816 int length = LocalPrototypeChainLength(*obj);
9817
9818 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009819 Handle<JSObject> jsproto = obj;
9820 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009821 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009822 jsproto->LocalLookup(*name, &result);
9823 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009824 // LookupResult is not GC safe as it holds raw object pointers.
9825 // GC can happen later in this code so put the required fields into
9826 // local variables using handles when required for later use.
9827 PropertyType result_type = result.type();
9828 Handle<Object> result_callback_obj;
9829 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009830 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
9831 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009832 }
9833 Smi* property_details = result.GetPropertyDetails().AsSmi();
9834 // DebugLookupResultValue can cause GC so details from LookupResult needs
9835 // to be copied to handles before this.
9836 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009837 Object* raw_value;
9838 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009839 DebugLookupResultValue(isolate->heap(), *obj, *name,
9840 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009841 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
9842 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009843 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009844
9845 // If the callback object is a fixed array then it contains JavaScript
9846 // getter and/or setter.
9847 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
9848 result_callback_obj->IsFixedArray();
9849 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009850 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009851 details->set(0, *value);
9852 details->set(1, property_details);
9853 if (hasJavaScriptAccessors) {
9854 details->set(2,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009855 caught_exception ? isolate->heap()->true_value()
9856 : isolate->heap()->false_value());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009857 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
9858 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
9859 }
9860
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009861 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009862 }
9863 if (i < length - 1) {
9864 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
9865 }
9866 }
9867
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009868 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009869}
9870
9871
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009872RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009873 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009874
9875 ASSERT(args.length() == 2);
9876
9877 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9878 CONVERT_ARG_CHECKED(String, name, 1);
9879
9880 LookupResult result;
9881 obj->Lookup(*name, &result);
9882 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009883 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009884 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009885 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009886}
9887
9888
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009889// Return the property type calculated from the property details.
9890// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009891RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009892 ASSERT(args.length() == 1);
9893 CONVERT_CHECKED(Smi, details, args[0]);
9894 PropertyType type = PropertyDetails(details).type();
9895 return Smi::FromInt(static_cast<int>(type));
9896}
9897
9898
9899// Return the property attribute calculated from the property details.
9900// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009901RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009902 ASSERT(args.length() == 1);
9903 CONVERT_CHECKED(Smi, details, args[0]);
9904 PropertyAttributes attributes = PropertyDetails(details).attributes();
9905 return Smi::FromInt(static_cast<int>(attributes));
9906}
9907
9908
9909// Return the property insertion index calculated from the property details.
9910// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009911RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009912 ASSERT(args.length() == 1);
9913 CONVERT_CHECKED(Smi, details, args[0]);
9914 int index = PropertyDetails(details).index();
9915 return Smi::FromInt(index);
9916}
9917
9918
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009919// Return property value from named interceptor.
9920// args[0]: object
9921// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009922RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009923 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009924 ASSERT(args.length() == 2);
9925 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9926 RUNTIME_ASSERT(obj->HasNamedInterceptor());
9927 CONVERT_ARG_CHECKED(String, name, 1);
9928
9929 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009930 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009931}
9932
9933
9934// Return element value from indexed interceptor.
9935// args[0]: object
9936// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009937RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009938 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009939 ASSERT(args.length() == 2);
9940 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9941 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
9942 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
9943
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009944 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009945}
9946
9947
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009948RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009949 ASSERT(args.length() >= 1);
9950 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00009951 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009952 if (isolate->debug()->break_id() == 0 ||
9953 break_id != isolate->debug()->break_id()) {
9954 return isolate->Throw(
9955 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009956 }
9957
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009958 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009959}
9960
9961
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009962RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009963 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009964 ASSERT(args.length() == 1);
9965
9966 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009967 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009968 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
9969 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009970 if (!maybe_result->ToObject(&result)) return maybe_result;
9971 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009972
9973 // Count all frames which are relevant to debugging stack trace.
9974 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009975 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009976 if (id == StackFrame::NO_ID) {
9977 // If there is no JavaScript stack frame count is 0.
9978 return Smi::FromInt(0);
9979 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +00009980
9981 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
9982 n += it.frame()->GetInlineCount();
9983 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009984 return Smi::FromInt(n);
9985}
9986
9987
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00009988class FrameInspector {
9989 public:
9990 FrameInspector(JavaScriptFrame* frame,
9991 int inlined_frame_index,
9992 Isolate* isolate)
9993 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
9994 // Calculate the deoptimized frame.
9995 if (frame->is_optimized()) {
9996 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
9997 frame, inlined_frame_index, isolate);
9998 }
9999 has_adapted_arguments_ = frame_->has_adapted_arguments();
10000 is_optimized_ = frame_->is_optimized();
10001 }
10002
10003 ~FrameInspector() {
10004 // Get rid of the calculated deoptimized frame if any.
10005 if (deoptimized_frame_ != NULL) {
10006 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10007 isolate_);
10008 }
10009 }
10010
10011 int GetParametersCount() {
10012 return is_optimized_
10013 ? deoptimized_frame_->parameters_count()
10014 : frame_->ComputeParametersCount();
10015 }
10016 int expression_count() { return deoptimized_frame_->expression_count(); }
10017 Object* GetFunction() {
10018 return is_optimized_
10019 ? deoptimized_frame_->GetFunction()
10020 : frame_->function();
10021 }
10022 Object* GetParameter(int index) {
10023 return is_optimized_
10024 ? deoptimized_frame_->GetParameter(index)
10025 : frame_->GetParameter(index);
10026 }
10027 Object* GetExpression(int index) {
10028 return is_optimized_
10029 ? deoptimized_frame_->GetExpression(index)
10030 : frame_->GetExpression(index);
10031 }
10032
10033 // To inspect all the provided arguments the frame might need to be
10034 // replaced with the arguments frame.
10035 void SetArgumentsFrame(JavaScriptFrame* frame) {
10036 ASSERT(has_adapted_arguments_);
10037 frame_ = frame;
10038 is_optimized_ = frame_->is_optimized();
10039 ASSERT(!is_optimized_);
10040 }
10041
10042 private:
10043 JavaScriptFrame* frame_;
10044 DeoptimizedFrameInfo* deoptimized_frame_;
10045 Isolate* isolate_;
10046 bool is_optimized_;
10047 bool has_adapted_arguments_;
10048
10049 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10050};
10051
10052
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010053static const int kFrameDetailsFrameIdIndex = 0;
10054static const int kFrameDetailsReceiverIndex = 1;
10055static const int kFrameDetailsFunctionIndex = 2;
10056static const int kFrameDetailsArgumentCountIndex = 3;
10057static const int kFrameDetailsLocalCountIndex = 4;
10058static const int kFrameDetailsSourcePositionIndex = 5;
10059static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010060static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010061static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010062static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010063
10064// Return an array with frame details
10065// args[0]: number: break id
10066// args[1]: number: frame index
10067//
10068// The array returned contains the following information:
10069// 0: Frame id
10070// 1: Receiver
10071// 2: Function
10072// 3: Argument count
10073// 4: Local count
10074// 5: Source position
10075// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010076// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010077// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010078// Arguments name, value
10079// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010080// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010081RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010082 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010083 ASSERT(args.length() == 2);
10084
10085 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010086 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010087 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10088 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010089 if (!maybe_check->ToObject(&check)) return maybe_check;
10090 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010091 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010092 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010093
10094 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010095 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010096 if (id == StackFrame::NO_ID) {
10097 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010098 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010099 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010100
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010101 int inlined_frame_index = 0; // Inlined frame index in optimized frame.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010102
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010103 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010104 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010105 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010106 if (index < count + it.frame()->GetInlineCount()) break;
10107 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010108 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010109 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010110
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010111 if (it.frame()->is_optimized()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010112 inlined_frame_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010113 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010114 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010115 FrameInspector frame_inspector(it.frame(), inlined_frame_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010116
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010117 // Traverse the saved contexts chain to find the active context for the
10118 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010119 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010120 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010121 save = save->prev();
10122 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010123 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010124
10125 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010126 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010127
10128 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010129 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010130 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010131
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010132 // Check for constructor frame. Inlined frames cannot be construct calls.
10133 bool inlined_frame =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010134 it.frame()->is_optimized() && inlined_frame_index != 0;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010135 bool constructor = !inlined_frame && it.frame()->IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010136
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010137 // Get scope info and read from it for local variable information.
10138 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010139 Handle<SharedFunctionInfo> shared(function->shared());
10140 Handle<SerializedScopeInfo> scope_info(shared->scope_info());
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010141 ASSERT(*scope_info != SerializedScopeInfo::Empty());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010142 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010143
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010144 // Get the locals names and values into a temporary array.
10145 //
10146 // TODO(1240907): Hide compiler-introduced stack variables
10147 // (e.g. .result)? For users of the debugger, they will probably be
10148 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010149 Handle<FixedArray> locals =
10150 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010151
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010152 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010153 int i = 0;
10154 for (; i < info.number_of_stack_slots(); ++i) {
10155 // Use the value from the stack.
10156 locals->set(i * 2, *info.LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010157 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010158 }
10159 if (i < info.NumberOfLocals()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010160 // Get the context containing declarations.
10161 Handle<Context> context(
10162 Context::cast(it.frame()->context())->declaration_context());
10163 for (; i < info.NumberOfLocals(); ++i) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010164 Handle<String> name = info.LocalName(i);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010165 locals->set(i * 2, *name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010166 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010167 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010168 }
10169 }
10170
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010171 // Check whether this frame is positioned at return. If not top
10172 // frame or if the frame is optimized it cannot be at a return.
10173 bool at_return = false;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010174 if (!it.frame()->is_optimized() && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010175 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010176 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010177
10178 // If positioned just before return find the value to be returned and add it
10179 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010180 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010181 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010182 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010183 Address internal_frame_sp = NULL;
10184 while (!it2.done()) {
10185 if (it2.frame()->is_internal()) {
10186 internal_frame_sp = it2.frame()->sp();
10187 } else {
10188 if (it2.frame()->is_java_script()) {
10189 if (it2.frame()->id() == it.frame()->id()) {
10190 // The internal frame just before the JavaScript frame contains the
10191 // value to return on top. A debug break at return will create an
10192 // internal frame to store the return value (eax/rax/r0) before
10193 // entering the debug break exit frame.
10194 if (internal_frame_sp != NULL) {
10195 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010196 Handle<Object>(Memory::Object_at(internal_frame_sp),
10197 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010198 break;
10199 }
10200 }
10201 }
10202
10203 // Indicate that the previous frame was not an internal frame.
10204 internal_frame_sp = NULL;
10205 }
10206 it2.Advance();
10207 }
10208 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010209
10210 // Now advance to the arguments adapter frame (if any). It contains all
10211 // the provided parameters whereas the function frame always have the number
10212 // of arguments matching the functions parameters. The rest of the
10213 // information (except for what is collected above) is the same.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010214 if (it.frame()->has_adapted_arguments()) {
10215 it.AdvanceToArgumentsFrame();
10216 frame_inspector.SetArgumentsFrame(it.frame());
10217 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010218
10219 // Find the number of arguments to fill. At least fill the number of
10220 // parameters for the function and fill more if more parameters are provided.
10221 int argument_count = info.number_of_parameters();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010222 if (argument_count < frame_inspector.GetParametersCount()) {
10223 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010224 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010225#ifdef DEBUG
10226 if (it.frame()->is_optimized()) {
10227 ASSERT_EQ(argument_count, frame_inspector.GetParametersCount());
10228 }
10229#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010230
10231 // Calculate the size of the result.
10232 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010233 2 * (argument_count + info.NumberOfLocals()) +
10234 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010235 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010236
10237 // Add the frame id.
10238 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10239
10240 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010241 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010242
10243 // Add the arguments count.
10244 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10245
10246 // Add the locals count
10247 details->set(kFrameDetailsLocalCountIndex,
10248 Smi::FromInt(info.NumberOfLocals()));
10249
10250 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010251 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010252 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10253 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010254 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010255 }
10256
10257 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010258 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010259
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010260 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010261 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010262
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010263 // Add flags to indicate information on whether this frame is
10264 // bit 0: invoked in the debugger context.
10265 // bit 1: optimized frame.
10266 // bit 2: inlined in optimized frame
10267 int flags = 0;
10268 if (*save->context() == *isolate->debug()->debug_context()) {
10269 flags |= 1 << 0;
10270 }
10271 if (it.frame()->is_optimized()) {
10272 flags |= 1 << 1;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010273 flags |= inlined_frame_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010274 }
10275 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010276
10277 // Fill the dynamic part.
10278 int details_index = kFrameDetailsFirstDynamicIndex;
10279
10280 // Add arguments name and value.
10281 for (int i = 0; i < argument_count; i++) {
10282 // Name of the argument.
10283 if (i < info.number_of_parameters()) {
10284 details->set(details_index++, *info.parameter_name(i));
10285 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010286 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010287 }
10288
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010289 // Parameter value.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010290 if (i < it.frame()->ComputeParametersCount()) {
10291 // Get the value from the stack.
10292 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010293 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010294 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010295 }
10296 }
10297
10298 // Add locals name and value from the temporary copy from the function frame.
10299 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
10300 details->set(details_index++, locals->get(i));
10301 }
10302
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010303 // Add the value being returned.
10304 if (at_return) {
10305 details->set(details_index++, *return_value);
10306 }
10307
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010308 // Add the receiver (same as in function frame).
10309 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10310 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010311 Handle<Object> receiver(it.frame()->receiver(), isolate);
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010312 if (!receiver->IsJSObject() && !shared->strict_mode() && !shared->native()) {
10313 // If the receiver is not a JSObject and the function is not a
10314 // builtin or strict-mode we have hit an optimization where a
10315 // value object is not converted into a wrapped JS objects. To
10316 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010317 // by creating correct wrapper object based on the calling frame's
10318 // global context.
10319 it.Advance();
10320 Handle<Context> calling_frames_global_context(
10321 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010322 receiver =
10323 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010324 }
10325 details->set(kFrameDetailsReceiverIndex, *receiver);
10326
10327 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010328 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010329}
10330
10331
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010332// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010333static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010334 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010335 Handle<SerializedScopeInfo> serialized_scope_info,
10336 ScopeInfo<>& scope_info,
10337 Handle<Context> context,
10338 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010339 // Fill all context locals to the context extension.
10340 for (int i = Context::MIN_CONTEXT_SLOTS;
10341 i < scope_info.number_of_context_slots();
10342 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +000010343 int context_index = serialized_scope_info->ContextSlotIndex(
10344 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010345
whesse@chromium.org7b260152011-06-20 15:33:18 +000010346 RETURN_IF_EMPTY_HANDLE_VALUE(
10347 isolate,
10348 SetProperty(scope_object,
10349 scope_info.context_slot_name(i),
10350 Handle<Object>(context->get(context_index), isolate),
10351 NONE,
10352 kNonStrictMode),
10353 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010354 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010355
10356 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010357}
10358
10359
10360// Create a plain JSObject which materializes the local scope for the specified
10361// frame.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010362static Handle<JSObject> MaterializeLocalScope(
10363 Isolate* isolate,
10364 JavaScriptFrame* frame,
10365 int inlined_frame_index) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010366 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010367 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010368 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10369 ScopeInfo<> scope_info(*serialized_scope_info);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010370 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010371
10372 // Allocate and initialize a JSObject with all the arguments, stack locals
10373 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010374 Handle<JSObject> local_scope =
10375 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010376
10377 // First fill all parameters.
10378 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010379 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010380 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010381 SetProperty(local_scope,
10382 scope_info.parameter_name(i),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010383 Handle<Object>(frame_inspector.GetParameter(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010384 NONE,
10385 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010386 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010387 }
10388
10389 // Second fill all stack locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010390 for (int i = 0; i < scope_info.number_of_stack_slots(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010391 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010392 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010393 SetProperty(local_scope,
10394 scope_info.stack_slot_name(i),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010395 Handle<Object>(frame_inspector.GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010396 NONE,
10397 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010398 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010399 }
10400
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010401 if (scope_info.number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
10402 // Third fill all context locals.
10403 Handle<Context> frame_context(Context::cast(frame->context()));
10404 Handle<Context> function_context(frame_context->declaration_context());
10405 if (!CopyContextLocalsToScopeObject(isolate,
10406 serialized_scope_info, scope_info,
10407 function_context, local_scope)) {
10408 return Handle<JSObject>();
10409 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010410
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010411 // Finally copy any properties from the function context extension.
10412 // These will be variables introduced by eval.
10413 if (function_context->closure() == *function) {
10414 if (function_context->has_extension() &&
10415 !function_context->IsGlobalContext()) {
10416 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
10417 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
10418 for (int i = 0; i < keys->length(); i++) {
10419 // Names of variables introduced by eval are strings.
10420 ASSERT(keys->get(i)->IsString());
10421 Handle<String> key(String::cast(keys->get(i)));
10422 RETURN_IF_EMPTY_HANDLE_VALUE(
10423 isolate,
10424 SetProperty(local_scope,
10425 key,
10426 GetProperty(ext, key),
10427 NONE,
10428 kNonStrictMode),
10429 Handle<JSObject>());
10430 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010431 }
10432 }
10433 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010434
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010435 return local_scope;
10436}
10437
10438
10439// Create a plain JSObject which materializes the closure content for the
10440// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010441static Handle<JSObject> MaterializeClosure(Isolate* isolate,
10442 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010443 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010444
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010445 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010446 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10447 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010448
10449 // Allocate and initialize a JSObject with all the content of theis function
10450 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010451 Handle<JSObject> closure_scope =
10452 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010453
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010454 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010455 if (!CopyContextLocalsToScopeObject(isolate,
10456 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010457 context, closure_scope)) {
10458 return Handle<JSObject>();
10459 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010460
10461 // Finally copy any properties from the function context extension. This will
10462 // be variables introduced by eval.
10463 if (context->has_extension()) {
10464 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010465 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010466 for (int i = 0; i < keys->length(); i++) {
10467 // Names of variables introduced by eval are strings.
10468 ASSERT(keys->get(i)->IsString());
10469 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010470 RETURN_IF_EMPTY_HANDLE_VALUE(
10471 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010472 SetProperty(closure_scope,
10473 key,
10474 GetProperty(ext, key),
10475 NONE,
10476 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010477 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010478 }
10479 }
10480
10481 return closure_scope;
10482}
10483
10484
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010485// Create a plain JSObject which materializes the scope for the specified
10486// catch context.
10487static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
10488 Handle<Context> context) {
10489 ASSERT(context->IsCatchContext());
10490 Handle<String> name(String::cast(context->extension()));
10491 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
10492 Handle<JSObject> catch_scope =
10493 isolate->factory()->NewJSObject(isolate->object_function());
10494 RETURN_IF_EMPTY_HANDLE_VALUE(
10495 isolate,
10496 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
10497 Handle<JSObject>());
10498 return catch_scope;
10499}
10500
10501
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010502// Iterate over the actual scopes visible from a stack frame. All scopes are
10503// backed by an actual context except the local scope, which is inserted
10504// "artifically" in the context chain.
10505class ScopeIterator {
10506 public:
10507 enum ScopeType {
10508 ScopeTypeGlobal = 0,
10509 ScopeTypeLocal,
10510 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010511 ScopeTypeClosure,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010512 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010513 };
10514
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010515 ScopeIterator(Isolate* isolate,
10516 JavaScriptFrame* frame,
10517 int inlined_frame_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010518 : isolate_(isolate),
10519 frame_(frame),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010520 inlined_frame_index_(inlined_frame_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010521 function_(JSFunction::cast(frame->function())),
10522 context_(Context::cast(frame->context())),
10523 local_done_(false),
10524 at_local_(false) {
10525
10526 // Check whether the first scope is actually a local scope.
10527 if (context_->IsGlobalContext()) {
10528 // If there is a stack slot for .result then this local scope has been
10529 // created for evaluating top level code and it is not a real local scope.
10530 // Checking for the existence of .result seems fragile, but the scope info
10531 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +000010532 int index = function_->shared()->scope_info()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010533 StackSlotIndex(isolate_->heap()->result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010534 at_local_ = index < 0;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010535 } else if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010536 at_local_ = true;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010537 } else if (context_->closure() != *function_) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010538 // The context_ is a with or catch block from the outer function.
10539 ASSERT(context_->IsWithContext() || context_->IsCatchContext());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010540 at_local_ = true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010541 }
10542 }
10543
10544 // More scopes?
10545 bool Done() { return context_.is_null(); }
10546
10547 // Move to the next scope.
10548 void Next() {
10549 // If at a local scope mark the local scope as passed.
10550 if (at_local_) {
10551 at_local_ = false;
10552 local_done_ = true;
10553
10554 // If the current context is not associated with the local scope the
10555 // current context is the next real scope, so don't move to the next
10556 // context in this case.
10557 if (context_->closure() != *function_) {
10558 return;
10559 }
10560 }
10561
10562 // The global scope is always the last in the chain.
10563 if (context_->IsGlobalContext()) {
10564 context_ = Handle<Context>();
10565 return;
10566 }
10567
10568 // Move to the next context.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010569 context_ = Handle<Context>(context_->previous(), isolate_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010570
10571 // If passing the local scope indicate that the current scope is now the
10572 // local scope.
10573 if (!local_done_ &&
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010574 (context_->IsGlobalContext() || context_->IsFunctionContext())) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010575 at_local_ = true;
10576 }
10577 }
10578
10579 // Return the type of the current scope.
10580 int Type() {
10581 if (at_local_) {
10582 return ScopeTypeLocal;
10583 }
10584 if (context_->IsGlobalContext()) {
10585 ASSERT(context_->global()->IsGlobalObject());
10586 return ScopeTypeGlobal;
10587 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010588 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010589 return ScopeTypeClosure;
10590 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010591 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010592 return ScopeTypeCatch;
10593 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010594 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010595 return ScopeTypeWith;
10596 }
10597
10598 // Return the JavaScript object with the content of the current scope.
10599 Handle<JSObject> ScopeObject() {
10600 switch (Type()) {
10601 case ScopeIterator::ScopeTypeGlobal:
10602 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010603 case ScopeIterator::ScopeTypeLocal:
10604 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010605 return MaterializeLocalScope(isolate_, frame_, inlined_frame_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010606 case ScopeIterator::ScopeTypeWith:
10607 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010608 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
10609 case ScopeIterator::ScopeTypeCatch:
10610 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010611 case ScopeIterator::ScopeTypeClosure:
10612 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010613 return MaterializeClosure(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010614 }
10615 UNREACHABLE();
10616 return Handle<JSObject>();
10617 }
10618
10619 // Return the context for this scope. For the local context there might not
10620 // be an actual context.
10621 Handle<Context> CurrentContext() {
10622 if (at_local_ && context_->closure() != *function_) {
10623 return Handle<Context>();
10624 }
10625 return context_;
10626 }
10627
10628#ifdef DEBUG
10629 // Debug print of the content of the current scope.
10630 void DebugPrint() {
10631 switch (Type()) {
10632 case ScopeIterator::ScopeTypeGlobal:
10633 PrintF("Global:\n");
10634 CurrentContext()->Print();
10635 break;
10636
10637 case ScopeIterator::ScopeTypeLocal: {
10638 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010639 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010640 scope_info.Print();
10641 if (!CurrentContext().is_null()) {
10642 CurrentContext()->Print();
10643 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010644 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010645 if (extension->IsJSContextExtensionObject()) {
10646 extension->Print();
10647 }
10648 }
10649 }
10650 break;
10651 }
10652
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010653 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010654 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010655 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010656 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010657
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010658 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000010659 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010660 CurrentContext()->extension()->Print();
10661 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000010662 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000010663
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010664 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010665 PrintF("Closure:\n");
10666 CurrentContext()->Print();
10667 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010668 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010669 if (extension->IsJSContextExtensionObject()) {
10670 extension->Print();
10671 }
10672 }
10673 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010674
10675 default:
10676 UNREACHABLE();
10677 }
10678 PrintF("\n");
10679 }
10680#endif
10681
10682 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010683 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010684 JavaScriptFrame* frame_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010685 int inlined_frame_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010686 Handle<JSFunction> function_;
10687 Handle<Context> context_;
10688 bool local_done_;
10689 bool at_local_;
10690
10691 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
10692};
10693
10694
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010695RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010696 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010697 ASSERT(args.length() == 2);
10698
10699 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010700 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010701 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10702 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010703 if (!maybe_check->ToObject(&check)) return maybe_check;
10704 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010705 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10706
10707 // Get the frame where the debugging is performed.
10708 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010709 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010710 JavaScriptFrame* frame = it.frame();
10711
10712 // Count the visible scopes.
10713 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010714 for (ScopeIterator it(isolate, frame, 0);
10715 !it.Done();
10716 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010717 n++;
10718 }
10719
10720 return Smi::FromInt(n);
10721}
10722
10723
10724static const int kScopeDetailsTypeIndex = 0;
10725static const int kScopeDetailsObjectIndex = 1;
10726static const int kScopeDetailsSize = 2;
10727
10728// Return an array with scope details
10729// args[0]: number: break id
10730// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010731// args[2]: number: inlined frame index
10732// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010733//
10734// The array returned contains the following information:
10735// 0: Scope type
10736// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010737RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010738 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010739 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010740
10741 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010742 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010743 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10744 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010745 if (!maybe_check->ToObject(&check)) return maybe_check;
10746 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010747 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010748 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
10749 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010750
10751 // Get the frame where the debugging is performed.
10752 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010753 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010754 JavaScriptFrame* frame = frame_it.frame();
10755
10756 // Find the requested scope.
10757 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010758 ScopeIterator it(isolate, frame, inlined_frame_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010759 for (; !it.Done() && n < index; it.Next()) {
10760 n++;
10761 }
10762 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010763 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010764 }
10765
10766 // Calculate the size of the result.
10767 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010768 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010769
10770 // Fill in scope details.
10771 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010772 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010773 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010774 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010775
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010776 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010777}
10778
10779
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010780RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010781 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010782 ASSERT(args.length() == 0);
10783
10784#ifdef DEBUG
10785 // Print the scopes for the top frame.
10786 StackFrameLocator locator;
10787 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010788 for (ScopeIterator it(isolate, frame, 0);
10789 !it.Done();
10790 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010791 it.DebugPrint();
10792 }
10793#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010794 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010795}
10796
10797
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010798RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010799 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010800 ASSERT(args.length() == 1);
10801
10802 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010803 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010804 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10805 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010806 if (!maybe_result->ToObject(&result)) return maybe_result;
10807 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010808
10809 // Count all archived V8 threads.
10810 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010811 for (ThreadState* thread =
10812 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010813 thread != NULL;
10814 thread = thread->Next()) {
10815 n++;
10816 }
10817
10818 // Total number of threads is current thread and archived threads.
10819 return Smi::FromInt(n + 1);
10820}
10821
10822
10823static const int kThreadDetailsCurrentThreadIndex = 0;
10824static const int kThreadDetailsThreadIdIndex = 1;
10825static const int kThreadDetailsSize = 2;
10826
10827// Return an array with thread details
10828// args[0]: number: break id
10829// args[1]: number: thread index
10830//
10831// The array returned contains the following information:
10832// 0: Is current thread?
10833// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010834RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010835 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010836 ASSERT(args.length() == 2);
10837
10838 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010839 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010840 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10841 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010842 if (!maybe_check->ToObject(&check)) return maybe_check;
10843 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010844 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
10845
10846 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010847 Handle<FixedArray> details =
10848 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010849
10850 // Thread index 0 is current thread.
10851 if (index == 0) {
10852 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010853 details->set(kThreadDetailsCurrentThreadIndex,
10854 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010855 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010856 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010857 } else {
10858 // Find the thread with the requested index.
10859 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010860 ThreadState* thread =
10861 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010862 while (index != n && thread != NULL) {
10863 thread = thread->Next();
10864 n++;
10865 }
10866 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010867 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010868 }
10869
10870 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010871 details->set(kThreadDetailsCurrentThreadIndex,
10872 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010873 details->set(kThreadDetailsThreadIdIndex,
10874 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010875 }
10876
10877 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010878 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010879}
10880
10881
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010882// Sets the disable break state
10883// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010884RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010885 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010886 ASSERT(args.length() == 1);
10887 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010888 isolate->debug()->set_disable_break(disable_break);
10889 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010890}
10891
10892
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010893RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010894 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010895 ASSERT(args.length() == 1);
10896
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010897 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10898 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010899 // Find the number of break points
10900 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010901 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010902 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010903 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010904 Handle<FixedArray>::cast(break_locations));
10905}
10906
10907
10908// Set a break point in a function
10909// args[0]: function
10910// args[1]: number: break source position (within the function source)
10911// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010912RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010913 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010914 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010915 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10916 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010917 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10918 RUNTIME_ASSERT(source_position >= 0);
10919 Handle<Object> break_point_object_arg = args.at<Object>(2);
10920
10921 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010922 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
10923 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010924
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010925 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010926}
10927
10928
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010929Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
10930 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010931 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010932 // Iterate the heap looking for SharedFunctionInfo generated from the
10933 // script. The inner most SharedFunctionInfo containing the source position
10934 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010935 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010936 // which is found is not compiled it is compiled and the heap is iterated
10937 // again as the compilation might create inner functions from the newly
10938 // compiled function and the actual requested break point might be in one of
10939 // these functions.
10940 bool done = false;
10941 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000010942 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010943 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010944 while (!done) {
10945 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010946 for (HeapObject* obj = iterator.next();
10947 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010948 if (obj->IsSharedFunctionInfo()) {
10949 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
10950 if (shared->script() == *script) {
10951 // If the SharedFunctionInfo found has the requested script data and
10952 // contains the source position it is a candidate.
10953 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +000010954 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010955 start_position = shared->start_position();
10956 }
10957 if (start_position <= position &&
10958 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +000010959 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010960 // candidate this is the new candidate.
10961 if (target.is_null()) {
10962 target_start_position = start_position;
10963 target = shared;
10964 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010965 if (target_start_position == start_position &&
10966 shared->end_position() == target->end_position()) {
10967 // If a top-level function contain only one function
10968 // declartion the source for the top-level and the function is
10969 // the same. In that case prefer the non top-level function.
10970 if (!shared->is_toplevel()) {
10971 target_start_position = start_position;
10972 target = shared;
10973 }
10974 } else if (target_start_position <= start_position &&
10975 shared->end_position() <= target->end_position()) {
10976 // This containment check includes equality as a function inside
10977 // a top-level function can share either start or end position
10978 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010979 target_start_position = start_position;
10980 target = shared;
10981 }
10982 }
10983 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010984 }
10985 }
10986 }
10987
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010988 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010989 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010990 }
10991
10992 // If the candidate found is compiled we are done. NOTE: when lazy
10993 // compilation of inner functions is introduced some additional checking
10994 // needs to be done here to compile inner functions.
10995 done = target->is_compiled();
10996 if (!done) {
10997 // If the candidate is not compiled compile it to reveal any inner
10998 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010999 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011000 }
11001 }
11002
11003 return *target;
11004}
11005
11006
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011007// Changes the state of a break point in a script and returns source position
11008// where break point was set. NOTE: Regarding performance see the NOTE for
11009// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011010// args[0]: script to set break point in
11011// args[1]: number: break source position (within the script source)
11012// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011013RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011014 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011015 ASSERT(args.length() == 3);
11016 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
11017 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11018 RUNTIME_ASSERT(source_position >= 0);
11019 Handle<Object> break_point_object_arg = args.at<Object>(2);
11020
11021 // Get the script from the script wrapper.
11022 RUNTIME_ASSERT(wrapper->value()->IsScript());
11023 Handle<Script> script(Script::cast(wrapper->value()));
11024
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011025 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011026 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011027 if (!result->IsUndefined()) {
11028 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11029 // Find position within function. The script position might be before the
11030 // source position of the first function.
11031 int position;
11032 if (shared->start_position() > source_position) {
11033 position = 0;
11034 } else {
11035 position = source_position - shared->start_position();
11036 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011037 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011038 position += shared->start_position();
11039 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011040 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011041 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011042}
11043
11044
11045// Clear a break point
11046// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011047RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011048 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011049 ASSERT(args.length() == 1);
11050 Handle<Object> break_point_object_arg = args.at<Object>(0);
11051
11052 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011053 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011054
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011055 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011056}
11057
11058
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011059// Change the state of break on exceptions.
11060// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11061// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011062RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011063 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011064 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011065 RUNTIME_ASSERT(args[0]->IsNumber());
11066 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011067
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011068 // If the number doesn't match an enum value, the ChangeBreakOnException
11069 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011070 ExceptionBreakType type =
11071 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011072 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011073 isolate->debug()->ChangeBreakOnException(type, enable);
11074 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011075}
11076
11077
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011078// Returns the state of break on exceptions
11079// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011080RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011081 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011082 ASSERT(args.length() == 1);
11083 RUNTIME_ASSERT(args[0]->IsNumber());
11084
11085 ExceptionBreakType type =
11086 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011087 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011088 return Smi::FromInt(result);
11089}
11090
11091
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011092// Prepare for stepping
11093// args[0]: break id for checking execution state
11094// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011095// args[2]: number of times to perform the step, for step out it is the number
11096// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011097RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011098 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011099 ASSERT(args.length() == 3);
11100 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011101 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011102 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11103 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011104 if (!maybe_check->ToObject(&check)) return maybe_check;
11105 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011106 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011107 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011108 }
11109
11110 // Get the step action and check validity.
11111 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11112 if (step_action != StepIn &&
11113 step_action != StepNext &&
11114 step_action != StepOut &&
11115 step_action != StepInMin &&
11116 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011117 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011118 }
11119
11120 // Get the number of steps.
11121 int step_count = NumberToInt32(args[2]);
11122 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011123 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011124 }
11125
ager@chromium.orga1645e22009-09-09 19:27:10 +000011126 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011127 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011128
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011129 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011130 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11131 step_count);
11132 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011133}
11134
11135
11136// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011137RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011138 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011139 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011140 isolate->debug()->ClearStepping();
11141 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011142}
11143
11144
11145// Creates a copy of the with context chain. The copy of the context chain is
11146// is linked to the function context supplied.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011147static Handle<Context> CopyWithContextChain(Isolate* isolate,
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011148 Handle<JSFunction> function,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011149 Handle<Context> current,
11150 Handle<Context> base) {
11151 // At the end of the chain. Return the base context to link to.
11152 if (current->IsFunctionContext() || current->IsGlobalContext()) {
11153 return base;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011154 }
11155
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011156 // Recursively copy the with and catch contexts.
11157 HandleScope scope(isolate);
11158 Handle<Context> previous(current->previous());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011159 Handle<Context> new_previous =
11160 CopyWithContextChain(isolate, function, previous, base);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011161 Handle<Context> new_current;
11162 if (current->IsCatchContext()) {
11163 Handle<String> name(String::cast(current->extension()));
11164 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11165 new_current =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011166 isolate->factory()->NewCatchContext(function,
11167 new_previous,
11168 name,
11169 thrown_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011170 } else {
11171 Handle<JSObject> extension(JSObject::cast(current->extension()));
11172 new_current =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011173 isolate->factory()->NewWithContext(function, new_previous, extension);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011174 }
11175 return scope.CloseAndEscape(new_current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011176}
11177
11178
11179// Helper function to find or create the arguments object for
11180// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011181static Handle<Object> GetArgumentsObject(Isolate* isolate,
11182 JavaScriptFrame* frame,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011183 int inlined_frame_index,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011184 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000011185 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011186 const ScopeInfo<>* sinfo,
11187 Handle<Context> function_context) {
11188 // Try to find the value of 'arguments' to pass as parameter. If it is not
11189 // found (that is the debugged function does not reference 'arguments' and
11190 // does not support eval) then create an 'arguments' object.
11191 int index;
11192 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011193 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011194 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011195 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011196 }
11197 }
11198
11199 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011200 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
11201 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011202 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011203 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011204 }
11205 }
11206
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011207 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
11208
11209 int length = frame_inspector.GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011210 Handle<JSObject> arguments =
11211 isolate->factory()->NewArgumentsObject(function, length);
11212 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011213
11214 AssertNoAllocation no_gc;
11215 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011216 for (int i = 0; i < length; i++) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011217 array->set(i, frame_inspector.GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011218 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011219 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011220 return arguments;
11221}
11222
11223
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011224static const char kSourceStr[] =
11225 "(function(arguments,__source__){return eval(__source__);})";
11226
11227
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011228// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000011229// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011230// extension part has all the parameters and locals of the function on the
11231// stack frame. A function which calls eval with the code to evaluate is then
11232// compiled in this context and called in this context. As this context
11233// replaces the context of the function on the stack frame a new (empty)
11234// function is created as well to be used as the closure for the context.
11235// This function and the context acts as replacements for the function on the
11236// stack frame presenting the same view of the values of parameters and
11237// local variables as if the piece of JavaScript was evaluated at the point
11238// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011239RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011240 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011241
11242 // Check the execution state and decode arguments frame and source to be
11243 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011244 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011245 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011246 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11247 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011248 if (!maybe_check_result->ToObject(&check_result)) {
11249 return maybe_check_result;
11250 }
11251 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011252 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011253 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
11254 CONVERT_ARG_CHECKED(String, source, 3);
11255 CONVERT_BOOLEAN_CHECKED(disable_break, args[4]);
11256 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011257
11258 // Handle the processing of break.
11259 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011260
11261 // Get the frame where the debugging is performed.
11262 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011263 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011264 JavaScriptFrame* frame = it.frame();
11265 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000011266 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011267 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011268
11269 // Traverse the saved contexts chain to find the active context for the
11270 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011271 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000011272 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011273 save = save->prev();
11274 }
11275 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011276 SaveContext savex(isolate);
11277 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011278
11279 // Create the (empty) function replacing the function on the stack frame for
11280 // the purpose of evaluating in the context created below. It is important
11281 // that this function does not describe any parameters and local variables
11282 // in the context. If it does then this will cause problems with the lookup
11283 // in Context::Lookup, where context slots for parameters and local variables
11284 // are looked at before the extension object.
11285 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011286 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
11287 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011288 go_between->set_context(function->context());
11289#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011290 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011291 ASSERT(go_between_sinfo.number_of_parameters() == 0);
11292 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
11293#endif
11294
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011295 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011296 Handle<JSObject> local_scope = MaterializeLocalScope(
11297 isolate, frame, inlined_frame_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011298 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011299
11300 // Allocate a new context for the debug evaluation and set the extension
11301 // object build.
11302 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011303 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11304 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011305 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011306 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011307 Handle<Context> frame_context(Context::cast(frame->context()));
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011308 Handle<Context> function_context(frame_context->declaration_context());
11309 context = CopyWithContextChain(isolate, go_between, frame_context, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011310
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011311 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011312 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011313 context =
11314 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011315 }
11316
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011317 // Wrap the evaluation statement in a new function compiled in the newly
11318 // created context. The function has one parameter which has to be called
11319 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000011320 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011321 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011322
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011323 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011324 isolate->factory()->NewStringFromAscii(
11325 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011326
11327 // Currently, the eval code will be executed in non-strict mode,
11328 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011329 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000011330 Compiler::CompileEval(function_source,
11331 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011332 context->IsGlobalContext(),
11333 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011334 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011335 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011336 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011337
11338 // Invoke the result of the compilation to get the evaluation function.
11339 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011340 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011341 Handle<Object> evaluation_function =
11342 Execution::Call(compiled_function, receiver, 0, NULL,
11343 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011344 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011345
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011346 Handle<Object> arguments = GetArgumentsObject(isolate,
11347 frame, inlined_frame_index,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011348 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011349 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011350
11351 // Invoke the evaluation function and return the result.
11352 const int argc = 2;
11353 Object** argv[argc] = { arguments.location(),
11354 Handle<Object>::cast(source).location() };
11355 Handle<Object> result =
11356 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
11357 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011358 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011359
11360 // Skip the global proxy as it has no properties and always delegates to the
11361 // real global object.
11362 if (result->IsJSGlobalProxy()) {
11363 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
11364 }
11365
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011366 return *result;
11367}
11368
11369
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011370RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011371 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011372
11373 // Check the execution state and decode arguments frame and source to be
11374 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011375 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011376 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011377 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11378 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011379 if (!maybe_check_result->ToObject(&check_result)) {
11380 return maybe_check_result;
11381 }
11382 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011383 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011384 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011385 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011386
11387 // Handle the processing of break.
11388 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011389
11390 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011391 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011392 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011393 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011394 top = top->prev();
11395 }
11396 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011397 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011398 }
11399
11400 // Get the global context now set to the top context from before the
11401 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011402 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011403
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011404 bool is_global = true;
11405
11406 if (additional_context->IsJSObject()) {
11407 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011408 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
11409 isolate->factory()->empty_string(),
11410 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011411 go_between->set_context(*context);
11412 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011413 isolate->factory()->NewFunctionContext(
11414 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011415 context->set_extension(JSObject::cast(*additional_context));
11416 is_global = false;
11417 }
11418
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011419 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011420 // Currently, the eval code will be executed in non-strict mode,
11421 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011422 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011423 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011424 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011425 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011426 Handle<JSFunction>(
11427 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
11428 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011429
11430 // Invoke the result of the compilation to get the evaluation function.
11431 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011432 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011433 Handle<Object> result =
11434 Execution::Call(compiled_function, receiver, 0, NULL,
11435 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011436 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011437 return *result;
11438}
11439
11440
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011441RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011442 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011443 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011444
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011445 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011446 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011447
11448 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000011449 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000011450 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
11451 // Get the script wrapper in a local handle before calling GetScriptWrapper,
11452 // because using
11453 // instances->set(i, *GetScriptWrapper(script))
11454 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
11455 // already have deferenced the instances handle.
11456 Handle<JSValue> wrapper = GetScriptWrapper(script);
11457 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011458 }
11459
11460 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011461 Handle<JSObject> result =
11462 isolate->factory()->NewJSObject(isolate->array_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011463 Handle<JSArray>::cast(result)->SetContent(*instances);
11464 return *result;
11465}
11466
11467
11468// Helper function used by Runtime_DebugReferencedBy below.
11469static int DebugReferencedBy(JSObject* target,
11470 Object* instance_filter, int max_references,
11471 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011472 JSFunction* arguments_function) {
11473 NoHandleAllocation ha;
11474 AssertNoAllocation no_alloc;
11475
11476 // Iterate the heap.
11477 int count = 0;
11478 JSObject* last = NULL;
11479 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011480 HeapObject* heap_obj = NULL;
11481 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011482 (max_references == 0 || count < max_references)) {
11483 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011484 if (heap_obj->IsJSObject()) {
11485 // Skip context extension objects and argument arrays as these are
11486 // checked in the context of functions using them.
11487 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000011488 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011489 obj->map()->constructor() == arguments_function) {
11490 continue;
11491 }
11492
11493 // Check if the JS object has a reference to the object looked for.
11494 if (obj->ReferencesObject(target)) {
11495 // Check instance filter if supplied. This is normally used to avoid
11496 // references from mirror objects (see Runtime_IsInPrototypeChain).
11497 if (!instance_filter->IsUndefined()) {
11498 Object* V = obj;
11499 while (true) {
11500 Object* prototype = V->GetPrototype();
11501 if (prototype->IsNull()) {
11502 break;
11503 }
11504 if (instance_filter == prototype) {
11505 obj = NULL; // Don't add this object.
11506 break;
11507 }
11508 V = prototype;
11509 }
11510 }
11511
11512 if (obj != NULL) {
11513 // Valid reference found add to instance array if supplied an update
11514 // count.
11515 if (instances != NULL && count < instances_size) {
11516 instances->set(count, obj);
11517 }
11518 last = obj;
11519 count++;
11520 }
11521 }
11522 }
11523 }
11524
11525 // Check for circular reference only. This can happen when the object is only
11526 // referenced from mirrors and has a circular reference in which case the
11527 // object is not really alive and would have been garbage collected if not
11528 // referenced from the mirror.
11529 if (count == 1 && last == target) {
11530 count = 0;
11531 }
11532
11533 // Return the number of referencing objects found.
11534 return count;
11535}
11536
11537
11538// Scan the heap for objects with direct references to an object
11539// args[0]: the object to find references to
11540// args[1]: constructor function for instances to exclude (Mirror)
11541// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011542RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011543 ASSERT(args.length() == 3);
11544
11545 // First perform a full GC in order to avoid references from dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011546 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011547
11548 // Check parameters.
11549 CONVERT_CHECKED(JSObject, target, args[0]);
11550 Object* instance_filter = args[1];
11551 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
11552 instance_filter->IsJSObject());
11553 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
11554 RUNTIME_ASSERT(max_references >= 0);
11555
11556 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011557 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011558 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011559 JSFunction* arguments_function =
11560 JSFunction::cast(arguments_boilerplate->map()->constructor());
11561
11562 // Get the number of referencing objects.
11563 int count;
11564 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011565 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011566
11567 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011568 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011569 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011570 if (!maybe_object->ToObject(&object)) return maybe_object;
11571 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011572 FixedArray* instances = FixedArray::cast(object);
11573
11574 // Fill the referencing objects.
11575 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011576 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011577
11578 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011579 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011580 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11581 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011582 if (!maybe_result->ToObject(&result)) return maybe_result;
11583 }
11584 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011585 return result;
11586}
11587
11588
11589// Helper function used by Runtime_DebugConstructedBy below.
11590static int DebugConstructedBy(JSFunction* constructor, int max_references,
11591 FixedArray* instances, int instances_size) {
11592 AssertNoAllocation no_alloc;
11593
11594 // Iterate the heap.
11595 int count = 0;
11596 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011597 HeapObject* heap_obj = NULL;
11598 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011599 (max_references == 0 || count < max_references)) {
11600 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011601 if (heap_obj->IsJSObject()) {
11602 JSObject* obj = JSObject::cast(heap_obj);
11603 if (obj->map()->constructor() == constructor) {
11604 // Valid reference found add to instance array if supplied an update
11605 // count.
11606 if (instances != NULL && count < instances_size) {
11607 instances->set(count, obj);
11608 }
11609 count++;
11610 }
11611 }
11612 }
11613
11614 // Return the number of referencing objects found.
11615 return count;
11616}
11617
11618
11619// Scan the heap for objects constructed by a specific function.
11620// args[0]: the constructor to find instances of
11621// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011622RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011623 ASSERT(args.length() == 2);
11624
11625 // First perform a full GC in order to avoid dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011626 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011627
11628 // Check parameters.
11629 CONVERT_CHECKED(JSFunction, constructor, args[0]);
11630 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
11631 RUNTIME_ASSERT(max_references >= 0);
11632
11633 // Get the number of referencing objects.
11634 int count;
11635 count = DebugConstructedBy(constructor, max_references, NULL, 0);
11636
11637 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011638 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011639 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011640 if (!maybe_object->ToObject(&object)) return maybe_object;
11641 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011642 FixedArray* instances = FixedArray::cast(object);
11643
11644 // Fill the referencing objects.
11645 count = DebugConstructedBy(constructor, max_references, instances, count);
11646
11647 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011648 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011649 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11650 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011651 if (!maybe_result->ToObject(&result)) return maybe_result;
11652 }
11653 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011654 return result;
11655}
11656
11657
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011658// Find the effective prototype object as returned by __proto__.
11659// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011660RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011661 ASSERT(args.length() == 1);
11662
11663 CONVERT_CHECKED(JSObject, obj, args[0]);
11664
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011665 // Use the __proto__ accessor.
11666 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011667}
11668
11669
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011670RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000011671 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011672 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011673 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011674}
11675
11676
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011677RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011678#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011679 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011680 ASSERT(args.length() == 1);
11681 // Get the function and make sure it is compiled.
11682 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011683 Handle<SharedFunctionInfo> shared(func->shared());
11684 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011685 return Failure::Exception();
11686 }
11687 func->code()->PrintLn();
11688#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011689 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011690}
ager@chromium.org9085a012009-05-11 19:22:57 +000011691
11692
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011693RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011694#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011695 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011696 ASSERT(args.length() == 1);
11697 // Get the function and make sure it is compiled.
11698 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011699 Handle<SharedFunctionInfo> shared(func->shared());
11700 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011701 return Failure::Exception();
11702 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011703 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011704#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011705 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011706}
11707
11708
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011709RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000011710 NoHandleAllocation ha;
11711 ASSERT(args.length() == 1);
11712
11713 CONVERT_CHECKED(JSFunction, f, args[0]);
11714 return f->shared()->inferred_name();
11715}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011716
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011717
11718static int FindSharedFunctionInfosForScript(Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011719 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011720 AssertNoAllocation no_allocations;
11721
11722 int counter = 0;
11723 int buffer_size = buffer->length();
11724 HeapIterator iterator;
11725 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
11726 ASSERT(obj != NULL);
11727 if (!obj->IsSharedFunctionInfo()) {
11728 continue;
11729 }
11730 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
11731 if (shared->script() != script) {
11732 continue;
11733 }
11734 if (counter < buffer_size) {
11735 buffer->set(counter, shared);
11736 }
11737 counter++;
11738 }
11739 return counter;
11740}
11741
11742// For a script finds all SharedFunctionInfo's in the heap that points
11743// to this script. Returns JSArray of SharedFunctionInfo wrapped
11744// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011745RUNTIME_FUNCTION(MaybeObject*,
11746 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011747 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011748 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011749 CONVERT_CHECKED(JSValue, script_value, args[0]);
11750
11751 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
11752
11753 const int kBufferSize = 32;
11754
11755 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011756 array = isolate->factory()->NewFixedArray(kBufferSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011757 int number = FindSharedFunctionInfosForScript(*script, *array);
11758 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011759 array = isolate->factory()->NewFixedArray(number);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011760 FindSharedFunctionInfosForScript(*script, *array);
11761 }
11762
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011763 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011764 result->set_length(Smi::FromInt(number));
11765
11766 LiveEdit::WrapSharedFunctionInfos(result);
11767
11768 return *result;
11769}
11770
11771// For a script calculates compilation information about all its functions.
11772// The script source is explicitly specified by the second argument.
11773// The source of the actual script is not used, however it is important that
11774// all generated code keeps references to this particular instance of script.
11775// Returns a JSArray of compilation infos. The array is ordered so that
11776// each function with all its descendant is always stored in a continues range
11777// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011778RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011779 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011780 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011781 CONVERT_CHECKED(JSValue, script, args[0]);
11782 CONVERT_ARG_CHECKED(String, source, 1);
11783 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
11784
11785 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
11786
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011787 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011788 return Failure::Exception();
11789 }
11790
11791 return result;
11792}
11793
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011794// Changes the source of the script to a new_source.
11795// If old_script_name is provided (i.e. is a String), also creates a copy of
11796// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011797RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011798 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011799 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011800 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
11801 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011802 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011803
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011804 CONVERT_CHECKED(Script, original_script_pointer,
11805 original_script_value->value());
11806 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011807
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011808 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
11809 new_source,
11810 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011811
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011812 if (old_script->IsScript()) {
11813 Handle<Script> script_handle(Script::cast(old_script));
11814 return *(GetScriptWrapper(script_handle));
11815 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011816 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011817 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011818}
11819
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011820
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011821RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011822 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011823 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011824 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
11825 return LiveEdit::FunctionSourceUpdated(shared_info);
11826}
11827
11828
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011829// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011830RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011831 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011832 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011833 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
11834 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
11835
ager@chromium.orgac091b72010-05-05 07:34:42 +000011836 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011837}
11838
11839// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011840RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011841 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011842 HandleScope scope(isolate);
11843 Handle<Object> function_object(args[0], isolate);
11844 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011845
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011846 if (function_object->IsJSValue()) {
11847 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
11848 if (script_object->IsJSValue()) {
11849 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011850 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011851 }
11852
11853 LiveEdit::SetFunctionScript(function_wrapper, script_object);
11854 } else {
11855 // Just ignore this. We may not have a SharedFunctionInfo for some functions
11856 // and we check it in this function.
11857 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011858
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011859 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011860}
11861
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011862
11863// In a code of a parent function replaces original function as embedded object
11864// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011865RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011866 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011867 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011868
11869 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
11870 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
11871 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
11872
11873 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
11874 subst_wrapper);
11875
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011876 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011877}
11878
11879
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011880// Updates positions of a shared function info (first parameter) according
11881// to script source change. Text change is described in second parameter as
11882// array of groups of 3 numbers:
11883// (change_begin, change_end, change_end_new_position).
11884// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011885RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011886 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011887 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011888 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
11889 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
11890
ager@chromium.orgac091b72010-05-05 07:34:42 +000011891 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011892}
11893
11894
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011895// For array of SharedFunctionInfo's (each wrapped in JSValue)
11896// checks that none of them have activations on stacks (of any thread).
11897// Returns array of the same length with corresponding results of
11898// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011899RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011900 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011901 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011902 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000011903 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011904
ager@chromium.org357bf652010-04-12 11:30:10 +000011905 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011906}
11907
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011908// Compares 2 strings line-by-line, then token-wise and returns diff in form
11909// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
11910// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011911RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011912 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011913 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011914 CONVERT_ARG_CHECKED(String, s1, 0);
11915 CONVERT_ARG_CHECKED(String, s2, 1);
11916
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011917 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011918}
11919
11920
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011921// A testing entry. Returns statement position which is the closest to
11922// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011923RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011924 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011925 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011926 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11927 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11928
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011929 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011930
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011931 if (code->kind() != Code::FUNCTION &&
11932 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011933 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011934 }
11935
11936 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011937 int closest_pc = 0;
11938 int distance = kMaxInt;
11939 while (!it.done()) {
11940 int statement_position = static_cast<int>(it.rinfo()->data());
11941 // Check if this break point is closer that what was previously found.
11942 if (source_position <= statement_position &&
11943 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000011944 closest_pc =
11945 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011946 distance = statement_position - source_position;
11947 // Check whether we can't get any closer.
11948 if (distance == 0) break;
11949 }
11950 it.next();
11951 }
11952
11953 return Smi::FromInt(closest_pc);
11954}
11955
11956
ager@chromium.org357bf652010-04-12 11:30:10 +000011957// Calls specified function with or without entering the debugger.
11958// This is used in unit tests to run code as if debugger is entered or simply
11959// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011960RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011961 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011962 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000011963 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11964 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
11965
11966 Handle<Object> result;
11967 bool pending_exception;
11968 {
11969 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011970 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011971 &pending_exception);
11972 } else {
11973 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011974 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011975 &pending_exception);
11976 }
11977 }
11978 if (!pending_exception) {
11979 return *result;
11980 } else {
11981 return Failure::Exception();
11982 }
11983}
11984
11985
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011986// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011987RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011988 CONVERT_CHECKED(String, arg, args[0]);
11989 SmartPointer<char> flags =
11990 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
11991 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011992 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011993}
11994
11995
11996// Performs a GC.
11997// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011998RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011999 isolate->heap()->CollectAllGarbage(true);
12000 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012001}
12002
12003
12004// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012005RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012006 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012007 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012008 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012009 }
12010 return Smi::FromInt(usage);
12011}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012012
12013
12014// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012015RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012016#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012017 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012018#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012019 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012020#endif
12021}
12022
12023
12024// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012025RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012026#ifdef LIVE_OBJECT_LIST
12027 return LiveObjectList::Capture();
12028#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012029 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012030#endif
12031}
12032
12033
12034// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012035RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012036#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012037 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012038 bool success = LiveObjectList::Delete(id);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012039 return success ? isolate->heap()->true_value() :
12040 isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012041#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012042 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012043#endif
12044}
12045
12046
12047// Generates the response to a debugger request for a dump of the objects
12048// contained in the difference between the captured live object lists
12049// specified by id1 and id2.
12050// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12051// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012052RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012053#ifdef LIVE_OBJECT_LIST
12054 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012055 CONVERT_SMI_ARG_CHECKED(id1, 0);
12056 CONVERT_SMI_ARG_CHECKED(id2, 1);
12057 CONVERT_SMI_ARG_CHECKED(start, 2);
12058 CONVERT_SMI_ARG_CHECKED(count, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012059 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
12060 EnterDebugger enter_debugger;
12061 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12062#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012063 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012064#endif
12065}
12066
12067
12068// Gets the specified object as requested by the debugger.
12069// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012070RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012071#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012072 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012073 Object* result = LiveObjectList::GetObj(obj_id);
12074 return result;
12075#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012076 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012077#endif
12078}
12079
12080
12081// Gets the obj id for the specified address if valid.
12082// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012083RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012084#ifdef LIVE_OBJECT_LIST
12085 HandleScope scope;
12086 CONVERT_ARG_CHECKED(String, address, 0);
12087 Object* result = LiveObjectList::GetObjId(address);
12088 return result;
12089#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012090 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012091#endif
12092}
12093
12094
12095// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012096RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012097#ifdef LIVE_OBJECT_LIST
12098 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012099 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012100 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12101 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12102 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12103 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
12104 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
12105
12106 Handle<JSObject> instance_filter;
12107 if (args[1]->IsJSObject()) {
12108 instance_filter = args.at<JSObject>(1);
12109 }
12110 bool verbose = false;
12111 if (args[2]->IsBoolean()) {
12112 verbose = args[2]->IsTrue();
12113 }
12114 int start = 0;
12115 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012116 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012117 }
12118 int limit = Smi::kMaxValue;
12119 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012120 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012121 }
12122
12123 return LiveObjectList::GetObjRetainers(obj_id,
12124 instance_filter,
12125 verbose,
12126 start,
12127 limit,
12128 filter_obj);
12129#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012130 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012131#endif
12132}
12133
12134
12135// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012136RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012137#ifdef LIVE_OBJECT_LIST
12138 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012139 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
12140 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012141 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
12142
12143 Handle<JSObject> instance_filter;
12144 if (args[2]->IsJSObject()) {
12145 instance_filter = args.at<JSObject>(2);
12146 }
12147
12148 Object* result =
12149 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
12150 return result;
12151#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012152 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012153#endif
12154}
12155
12156
12157// Generates the response to a debugger request for a list of all
12158// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012159RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012160#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012161 CONVERT_SMI_ARG_CHECKED(start, 0);
12162 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012163 return LiveObjectList::Info(start, count);
12164#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012165 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012166#endif
12167}
12168
12169
12170// Gets a dump of the specified object as requested by the debugger.
12171// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012172RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012173#ifdef LIVE_OBJECT_LIST
12174 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012175 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012176 Object* result = LiveObjectList::PrintObj(obj_id);
12177 return result;
12178#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012179 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012180#endif
12181}
12182
12183
12184// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012185RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012186#ifdef LIVE_OBJECT_LIST
12187 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012188 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012189#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012190 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012191#endif
12192}
12193
12194
12195// Generates the response to a debugger request for a summary of the types
12196// of objects in the difference between the captured live object lists
12197// specified by id1 and id2.
12198// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12199// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012200RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012201#ifdef LIVE_OBJECT_LIST
12202 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012203 CONVERT_SMI_ARG_CHECKED(id1, 0);
12204 CONVERT_SMI_ARG_CHECKED(id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012205 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
12206
12207 EnterDebugger enter_debugger;
12208 return LiveObjectList::Summarize(id1, id2, filter_obj);
12209#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012210 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012211#endif
12212}
12213
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012214#endif // ENABLE_DEBUGGER_SUPPORT
12215
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012216
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012217RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012218 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012219 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012220 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012221}
12222
12223
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012224RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012225 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012226 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012227 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012228}
12229
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012230
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012231// Finds the script object from the script data. NOTE: This operation uses
12232// heap traversal to find the function generated for the source position
12233// for the requested break point. For lazily compiled functions several heap
12234// traversals might be required rendering this operation as a rather slow
12235// operation. However for setting break points which is normally done through
12236// some kind of user interaction the performance is not crucial.
12237static Handle<Object> Runtime_GetScriptFromScriptName(
12238 Handle<String> script_name) {
12239 // Scan the heap for Script objects to find the script with the requested
12240 // script data.
12241 Handle<Script> script;
12242 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012243 HeapObject* obj = NULL;
12244 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012245 // If a script is found check if it has the script data requested.
12246 if (obj->IsScript()) {
12247 if (Script::cast(obj)->name()->IsString()) {
12248 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
12249 script = Handle<Script>(Script::cast(obj));
12250 }
12251 }
12252 }
12253 }
12254
12255 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012256 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012257
12258 // Return the script found.
12259 return GetScriptWrapper(script);
12260}
12261
12262
12263// Get the script object from script data. NOTE: Regarding performance
12264// see the NOTE for GetScriptFromScriptData.
12265// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012266RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012267 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012268
12269 ASSERT(args.length() == 1);
12270
12271 CONVERT_CHECKED(String, script_name, args[0]);
12272
12273 // Find the requested script.
12274 Handle<Object> result =
12275 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
12276 return *result;
12277}
12278
12279
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012280// Determines whether the given stack frame should be displayed in
12281// a stack trace. The caller is the error constructor that asked
12282// for the stack trace to be collected. The first time a construct
12283// call to this function is encountered it is skipped. The seen_caller
12284// in/out parameter is used to remember if the caller has been seen
12285// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012286static bool ShowFrameInStackTrace(StackFrame* raw_frame,
12287 Object* caller,
12288 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012289 // Only display JS frames.
12290 if (!raw_frame->is_java_script())
12291 return false;
12292 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
12293 Object* raw_fun = frame->function();
12294 // Not sure when this can happen but skip it just in case.
12295 if (!raw_fun->IsJSFunction())
12296 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012297 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012298 *seen_caller = true;
12299 return false;
12300 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012301 // Skip all frames until we've seen the caller.
12302 if (!(*seen_caller)) return false;
12303 // Also, skip the most obvious builtin calls. We recognize builtins
12304 // as (1) functions called with the builtins object as the receiver and
12305 // as (2) functions from native scripts called with undefined as the
12306 // receiver (direct calls to helper functions in the builtins
12307 // code). Some builtin calls (such as Number.ADD which is invoked
12308 // using 'call') are very difficult to recognize so we're leaving
12309 // them in for now.
12310 if (frame->receiver()->IsJSBuiltinsObject()) {
12311 return false;
12312 }
12313 JSFunction* fun = JSFunction::cast(raw_fun);
12314 Object* raw_script = fun->shared()->script();
12315 if (frame->receiver()->IsUndefined() && raw_script->IsScript()) {
12316 int script_type = Script::cast(raw_script)->type()->value();
12317 return script_type != Script::TYPE_NATIVE;
12318 }
12319 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012320}
12321
12322
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012323// Collect the raw data for a stack trace. Returns an array of 4
12324// element segments each containing a receiver, function, code and
12325// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012326RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012327 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012328 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012329 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
12330
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012331 HandleScope scope(isolate);
12332 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012333
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000012334 limit = Max(limit, 0); // Ensure that limit is not negative.
12335 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012336 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012337 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012338
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012339 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012340 // If the caller parameter is a function we skip frames until we're
12341 // under it before starting to collect.
12342 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012343 int cursor = 0;
12344 int frames_seen = 0;
12345 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012346 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012347 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012348 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012349 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012350 // Set initial size to the maximum inlining level + 1 for the outermost
12351 // function.
12352 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012353 frame->Summarize(&frames);
12354 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012355 if (cursor + 4 > elements->length()) {
12356 int new_capacity = JSObject::NewElementsCapacity(elements->length());
12357 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012358 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012359 for (int i = 0; i < cursor; i++) {
12360 new_elements->set(i, elements->get(i));
12361 }
12362 elements = new_elements;
12363 }
12364 ASSERT(cursor + 4 <= elements->length());
12365
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012366 Handle<Object> recv = frames[i].receiver();
12367 Handle<JSFunction> fun = frames[i].function();
12368 Handle<Code> code = frames[i].code();
12369 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012370 elements->set(cursor++, *recv);
12371 elements->set(cursor++, *fun);
12372 elements->set(cursor++, *code);
12373 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012374 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012375 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012376 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012377 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012378 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012379 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012380 return *result;
12381}
12382
12383
ager@chromium.org3811b432009-10-28 14:53:37 +000012384// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012385RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000012386 ASSERT_EQ(args.length(), 0);
12387
12388 NoHandleAllocation ha;
12389
12390 const char* version_string = v8::V8::GetVersion();
12391
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012392 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
12393 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000012394}
12395
12396
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012397RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012398 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012399 OS::PrintError("abort: %s\n",
12400 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012401 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012402 OS::Abort();
12403 UNREACHABLE();
12404 return NULL;
12405}
12406
12407
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012408RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012409 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012410 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012411 Object* key = args[1];
12412
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012413 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012414 Object* o = cache->get(finger_index);
12415 if (o == key) {
12416 // The fastest case: hit the same place again.
12417 return cache->get(finger_index + 1);
12418 }
12419
12420 for (int i = finger_index - 2;
12421 i >= JSFunctionResultCache::kEntriesIndex;
12422 i -= 2) {
12423 o = cache->get(i);
12424 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012425 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012426 return cache->get(i + 1);
12427 }
12428 }
12429
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012430 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012431 ASSERT(size <= cache->length());
12432
12433 for (int i = size - 2; i > finger_index; i -= 2) {
12434 o = cache->get(i);
12435 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012436 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012437 return cache->get(i + 1);
12438 }
12439 }
12440
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012441 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012442 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012443
12444 Handle<JSFunctionResultCache> cache_handle(cache);
12445 Handle<Object> key_handle(key);
12446 Handle<Object> value;
12447 {
12448 Handle<JSFunction> factory(JSFunction::cast(
12449 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
12450 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012451 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012452 // This handle is nor shared, nor used later, so it's safe.
12453 Object** argv[] = { key_handle.location() };
12454 bool pending_exception = false;
12455 value = Execution::Call(factory,
12456 receiver,
12457 1,
12458 argv,
12459 &pending_exception);
12460 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012461 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012462
12463#ifdef DEBUG
12464 cache_handle->JSFunctionResultCacheVerify();
12465#endif
12466
12467 // Function invocation may have cleared the cache. Reread all the data.
12468 finger_index = cache_handle->finger_index();
12469 size = cache_handle->size();
12470
12471 // If we have spare room, put new data into it, otherwise evict post finger
12472 // entry which is likely to be the least recently used.
12473 int index = -1;
12474 if (size < cache_handle->length()) {
12475 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
12476 index = size;
12477 } else {
12478 index = finger_index + JSFunctionResultCache::kEntrySize;
12479 if (index == cache_handle->length()) {
12480 index = JSFunctionResultCache::kEntriesIndex;
12481 }
12482 }
12483
12484 ASSERT(index % 2 == 0);
12485 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
12486 ASSERT(index < cache_handle->length());
12487
12488 cache_handle->set(index, *key_handle);
12489 cache_handle->set(index + 1, *value);
12490 cache_handle->set_finger_index(index);
12491
12492#ifdef DEBUG
12493 cache_handle->JSFunctionResultCacheVerify();
12494#endif
12495
12496 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012497}
12498
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012499
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012500RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012501 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012502 CONVERT_ARG_CHECKED(String, type, 0);
12503 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012504 return *isolate->factory()->NewJSMessageObject(
12505 type,
12506 arguments,
12507 0,
12508 0,
12509 isolate->factory()->undefined_value(),
12510 isolate->factory()->undefined_value(),
12511 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012512}
12513
12514
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012515RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012516 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12517 return message->type();
12518}
12519
12520
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012521RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012522 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12523 return message->arguments();
12524}
12525
12526
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012527RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012528 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12529 return Smi::FromInt(message->start_position());
12530}
12531
12532
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012533RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012534 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12535 return message->script();
12536}
12537
12538
kasper.lund44510672008-07-25 07:37:58 +000012539#ifdef DEBUG
12540// ListNatives is ONLY used by the fuzz-natives.js in debug mode
12541// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012542RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000012543 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012544 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012545#define COUNT_ENTRY(Name, argc, ressize) + 1
12546 int entry_count = 0
12547 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
12548 INLINE_FUNCTION_LIST(COUNT_ENTRY)
12549 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
12550#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012551 Factory* factory = isolate->factory();
12552 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012553 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012554 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000012555#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012556 { \
12557 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012558 Handle<String> name; \
12559 /* Inline runtime functions have an underscore in front of the name. */ \
12560 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012561 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012562 Vector<const char>("_" #Name, StrLength("_" #Name))); \
12563 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012564 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012565 Vector<const char>(#Name, StrLength(#Name))); \
12566 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012567 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012568 pair_elements->set(0, *name); \
12569 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012570 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012571 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012572 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012573 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012574 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012575 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012576 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012577 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012578#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012579 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012580 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012581 return *result;
12582}
kasper.lund44510672008-07-25 07:37:58 +000012583#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012584
12585
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012586RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012587 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012588 CONVERT_CHECKED(String, format, args[0]);
12589 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012590 Vector<const char> chars = format->ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012591 LOGGER->LogRuntime(chars, elms);
12592 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012593}
12594
12595
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012596RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012597 UNREACHABLE(); // implemented as macro in the parser
12598 return NULL;
12599}
12600
12601
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012602#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
12603 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
12604 CONVERT_CHECKED(JSObject, obj, args[0]); \
12605 return isolate->heap()->ToBoolean(obj->Has##Name()); \
12606 }
12607
12608ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
12609ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
12610ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
12611ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
12612ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
12613ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
12614ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
12615ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
12616ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
12617ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
12618ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
12619ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
12620ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
12621
12622#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
12623
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012624// ----------------------------------------------------------------------------
12625// Implementation of Runtime
12626
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012627#define F(name, number_of_args, result_size) \
12628 { Runtime::k##name, Runtime::RUNTIME, #name, \
12629 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012630
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012631
12632#define I(name, number_of_args, result_size) \
12633 { Runtime::kInline##name, Runtime::INLINE, \
12634 "_" #name, NULL, number_of_args, result_size },
12635
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012636static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012637 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012638 INLINE_FUNCTION_LIST(I)
12639 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012640};
12641
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012642
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012643MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
12644 Object* dictionary) {
12645 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012646 ASSERT(dictionary != NULL);
12647 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
12648 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000012649 Object* name_symbol;
12650 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012651 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012652 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
12653 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012654 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012655 { MaybeObject* maybe_dictionary = string_dictionary->Add(
12656 String::cast(name_symbol),
12657 Smi::FromInt(i),
12658 PropertyDetails(NONE, NORMAL));
12659 if (!maybe_dictionary->ToObject(&dictionary)) {
12660 // Non-recoverable failure. Calling code must restart heap
12661 // initialization.
12662 return maybe_dictionary;
12663 }
12664 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012665 }
12666 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012667}
12668
12669
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012670const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
12671 Heap* heap = name->GetHeap();
12672 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012673 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012674 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012675 int function_index = Smi::cast(smi_index)->value();
12676 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012677 }
12678 return NULL;
12679}
12680
12681
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012682const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012683 return &(kIntrinsicFunctions[static_cast<int>(id)]);
12684}
12685
12686
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012687void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012688 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012689 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012690 if (failure->IsRetryAfterGC()) {
12691 // Try to do a garbage collection; ignore it if it fails. The C
12692 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012693 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012694 } else {
12695 // Handle last resort GC and make sure to allow future allocations
12696 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012697 isolate->counters()->gc_last_resort_from_js()->Increment();
12698 isolate->heap()->CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012699 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012700}
12701
12702
12703} } // namespace v8::internal