blob: 0ce58366d2c5441734325fa79a9702eac56c6860 [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
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000618RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000619 NoHandleAllocation ha;
620 ASSERT(args.length() == 1);
621 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000622 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000623 return JSObject::cast(obj)->class_name();
624}
625
ager@chromium.org7c537e22008-10-16 08:43:32 +0000626
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000627RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
628 NoHandleAllocation ha;
629 ASSERT(args.length() == 1);
630 Object* obj = args[0];
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000631 do {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000632 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000633 } while (obj->IsJSObject() &&
634 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000635 return obj;
636}
637
638
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000639RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000640 NoHandleAllocation ha;
641 ASSERT(args.length() == 2);
642 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
643 Object* O = args[0];
644 Object* V = args[1];
645 while (true) {
646 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000647 if (prototype->IsNull()) return isolate->heap()->false_value();
648 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000649 V = prototype;
650 }
651}
652
653
ager@chromium.org9085a012009-05-11 19:22:57 +0000654// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000655RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000656 NoHandleAllocation ha;
657 ASSERT(args.length() == 2);
658 CONVERT_CHECKED(JSObject, jsobject, args[0]);
659 CONVERT_CHECKED(JSObject, proto, args[1]);
660
661 // Sanity checks. The old prototype (that we are replacing) could
662 // theoretically be null, but if it is not null then check that we
663 // didn't already install a hidden prototype here.
664 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
665 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
666 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
667
668 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000669 Object* map_or_failure;
670 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
671 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
672 return maybe_map_or_failure;
673 }
674 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000675 Map* new_proto_map = Map::cast(map_or_failure);
676
lrn@chromium.org303ada72010-10-27 09:33:13 +0000677 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
678 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
679 return maybe_map_or_failure;
680 }
681 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000682 Map* new_map = Map::cast(map_or_failure);
683
684 // Set proto's prototype to be the old prototype of the object.
685 new_proto_map->set_prototype(jsobject->GetPrototype());
686 proto->set_map(new_proto_map);
687 new_proto_map->set_is_hidden_prototype();
688
689 // Set the object's prototype to proto.
690 new_map->set_prototype(proto);
691 jsobject->set_map(new_map);
692
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000693 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000694}
695
696
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000697RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000698 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000699 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000700 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000701 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000702}
703
704
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000705// Recursively traverses hidden prototypes if property is not found
706static void GetOwnPropertyImplementation(JSObject* obj,
707 String* name,
708 LookupResult* result) {
709 obj->LocalLookupRealNamedProperty(name, result);
710
711 if (!result->IsProperty()) {
712 Object* proto = obj->GetPrototype();
713 if (proto->IsJSObject() &&
714 JSObject::cast(proto)->map()->is_hidden_prototype())
715 GetOwnPropertyImplementation(JSObject::cast(proto),
716 name, result);
717 }
718}
719
720
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000721static bool CheckAccessException(LookupResult* result,
722 v8::AccessType access_type) {
723 if (result->type() == CALLBACKS) {
724 Object* callback = result->GetCallbackObject();
725 if (callback->IsAccessorInfo()) {
726 AccessorInfo* info = AccessorInfo::cast(callback);
727 bool can_access =
728 (access_type == v8::ACCESS_HAS &&
729 (info->all_can_read() || info->all_can_write())) ||
730 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
731 (access_type == v8::ACCESS_SET && info->all_can_write());
732 return can_access;
733 }
734 }
735
736 return false;
737}
738
739
740static bool CheckAccess(JSObject* obj,
741 String* name,
742 LookupResult* result,
743 v8::AccessType access_type) {
744 ASSERT(result->IsProperty());
745
746 JSObject* holder = result->holder();
747 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000748 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000749 while (true) {
750 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000751 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000752 // Access check callback denied the access, but some properties
753 // can have a special permissions which override callbacks descision
754 // (currently see v8::AccessControl).
755 break;
756 }
757
758 if (current == holder) {
759 return true;
760 }
761
762 current = JSObject::cast(current->GetPrototype());
763 }
764
765 // API callbacks can have per callback access exceptions.
766 switch (result->type()) {
767 case CALLBACKS: {
768 if (CheckAccessException(result, access_type)) {
769 return true;
770 }
771 break;
772 }
773 case INTERCEPTOR: {
774 // If the object has an interceptor, try real named properties.
775 // Overwrite the result to fetch the correct property later.
776 holder->LookupRealNamedProperty(name, result);
777 if (result->IsProperty()) {
778 if (CheckAccessException(result, access_type)) {
779 return true;
780 }
781 }
782 break;
783 }
784 default:
785 break;
786 }
787
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000788 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000789 return false;
790}
791
792
793// TODO(1095): we should traverse hidden prototype hierachy as well.
794static bool CheckElementAccess(JSObject* obj,
795 uint32_t index,
796 v8::AccessType access_type) {
797 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000798 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000799 return false;
800 }
801
802 return true;
803}
804
805
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000806// Enumerator used as indices into the array returned from GetOwnProperty
807enum PropertyDescriptorIndices {
808 IS_ACCESSOR_INDEX,
809 VALUE_INDEX,
810 GETTER_INDEX,
811 SETTER_INDEX,
812 WRITABLE_INDEX,
813 ENUMERABLE_INDEX,
814 CONFIGURABLE_INDEX,
815 DESCRIPTOR_SIZE
816};
817
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000818// Returns an array with the property description:
819// if args[1] is not a property on args[0]
820// returns undefined
821// if args[1] is a data property on args[0]
822// [false, value, Writeable, Enumerable, Configurable]
823// if args[1] is an accessor on args[0]
824// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000825RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000826 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000827 Heap* heap = isolate->heap();
828 HandleScope scope(isolate);
829 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
830 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000831 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000832 CONVERT_ARG_CHECKED(JSObject, obj, 0);
833 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000834
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000835 // This could be an element.
836 uint32_t index;
837 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000838 switch (obj->HasLocalElement(index)) {
839 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000840 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000841
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000842 case JSObject::STRING_CHARACTER_ELEMENT: {
843 // Special handling of string objects according to ECMAScript 5
844 // 15.5.5.2. Note that this might be a string object with elements
845 // other than the actual string value. This is covered by the
846 // subsequent cases.
847 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
848 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000849 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000850
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000851 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000852 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000853 elms->set(WRITABLE_INDEX, heap->false_value());
854 elms->set(ENUMERABLE_INDEX, heap->false_value());
855 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000856 return *desc;
857 }
858
859 case JSObject::INTERCEPTED_ELEMENT:
860 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000861 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000862 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000863 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000864 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000865 elms->set(WRITABLE_INDEX, heap->true_value());
866 elms->set(ENUMERABLE_INDEX, heap->true_value());
867 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000868 return *desc;
869 }
870
871 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000872 Handle<JSObject> holder = obj;
873 if (obj->IsJSGlobalProxy()) {
874 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000875 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000876 ASSERT(proto->IsJSGlobalObject());
877 holder = Handle<JSObject>(JSObject::cast(proto));
878 }
whesse@chromium.org7b260152011-06-20 15:33:18 +0000879 FixedArray* elements = FixedArray::cast(holder->elements());
880 NumberDictionary* dictionary = NULL;
881 if (elements->map() == heap->non_strict_arguments_elements_map()) {
882 dictionary = NumberDictionary::cast(elements->get(1));
883 } else {
884 dictionary = NumberDictionary::cast(elements);
885 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000886 int entry = dictionary->FindEntry(index);
887 ASSERT(entry != NumberDictionary::kNotFound);
888 PropertyDetails details = dictionary->DetailsAt(entry);
889 switch (details.type()) {
890 case CALLBACKS: {
891 // This is an accessor property with getter and/or setter.
892 FixedArray* callbacks =
893 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000894 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000895 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
896 elms->set(GETTER_INDEX, callbacks->get(0));
897 }
898 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
899 elms->set(SETTER_INDEX, callbacks->get(1));
900 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000901 break;
902 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000903 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000904 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000905 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000906 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000907 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000908 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000909 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000910 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000911 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000912 default:
913 UNREACHABLE();
914 break;
915 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000916 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
917 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000918 return *desc;
919 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000920 }
921 }
922
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000923 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000924 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000925
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000926 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000927 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000928 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000929
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000930 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000931 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000932 }
933
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000934 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
935 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000936
937 bool is_js_accessor = (result.type() == CALLBACKS) &&
938 (result.GetCallbackObject()->IsFixedArray());
939
940 if (is_js_accessor) {
941 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000942 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000943
944 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
945 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
946 elms->set(GETTER_INDEX, structure->get(0));
947 }
948 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
949 elms->set(SETTER_INDEX, structure->get(1));
950 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000951 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000952 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
953 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000954
955 PropertyAttributes attrs;
956 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000957 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000958 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
959 if (!maybe_value->ToObject(&value)) return maybe_value;
960 }
961 elms->set(VALUE_INDEX, value);
962 }
963
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000964 return *desc;
965}
966
967
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000968RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000969 ASSERT(args.length() == 1);
970 CONVERT_CHECKED(JSObject, obj, args[0]);
971 return obj->PreventExtensions();
972}
973
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000974
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000975RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000976 ASSERT(args.length() == 1);
977 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000978 if (obj->IsJSGlobalProxy()) {
979 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000980 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000981 ASSERT(proto->IsJSGlobalObject());
982 obj = JSObject::cast(proto);
983 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000984 return obj->map()->is_extensible() ? isolate->heap()->true_value()
985 : isolate->heap()->false_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000986}
987
988
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000989RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000990 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000991 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000992 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
993 CONVERT_ARG_CHECKED(String, pattern, 1);
994 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000995 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
996 if (result.is_null()) return Failure::Exception();
997 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000998}
999
1000
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001001RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001002 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001003 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001004 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001005 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001006}
1007
1008
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001009RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001010 ASSERT(args.length() == 1);
1011 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001012 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001013 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001014}
1015
1016
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001017RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001018 ASSERT(args.length() == 2);
1019 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001020 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001021 int index = field->value();
1022 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1023 InstanceType type = templ->map()->instance_type();
1024 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1025 type == OBJECT_TEMPLATE_INFO_TYPE);
1026 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001027 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001028 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1029 } else {
1030 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1031 }
1032 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001033}
1034
1035
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001036RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001037 ASSERT(args.length() == 1);
1038 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001039 Map* old_map = object->map();
1040 bool needs_access_checks = old_map->is_access_check_needed();
1041 if (needs_access_checks) {
1042 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001043 Object* new_map;
1044 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1045 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1046 }
ager@chromium.org32912102009-01-16 10:38:43 +00001047
1048 Map::cast(new_map)->set_is_access_check_needed(false);
1049 object->set_map(Map::cast(new_map));
1050 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001051 return needs_access_checks ? isolate->heap()->true_value()
1052 : isolate->heap()->false_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001053}
1054
1055
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001056RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001057 ASSERT(args.length() == 1);
1058 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001059 Map* old_map = object->map();
1060 if (!old_map->is_access_check_needed()) {
1061 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001062 Object* new_map;
1063 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1064 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1065 }
ager@chromium.org32912102009-01-16 10:38:43 +00001066
1067 Map::cast(new_map)->set_is_access_check_needed(true);
1068 object->set_map(Map::cast(new_map));
1069 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001070 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001071}
1072
1073
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001074static Failure* ThrowRedeclarationError(Isolate* isolate,
1075 const char* type,
1076 Handle<String> name) {
1077 HandleScope scope(isolate);
1078 Handle<Object> type_handle =
1079 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001080 Handle<Object> args[2] = { type_handle, name };
1081 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001082 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1083 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001084}
1085
1086
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001087RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001088 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001089 HandleScope scope(isolate);
1090 Handle<GlobalObject> global = Handle<GlobalObject>(
1091 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001092
ager@chromium.org3811b432009-10-28 14:53:37 +00001093 Handle<Context> context = args.at<Context>(0);
1094 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001095 bool is_eval = args.smi_at(2) == 1;
1096 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(3));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001097 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001098
1099 // Compute the property attributes. According to ECMA-262, section
1100 // 13, page 71, the property must be read-only and
1101 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1102 // property as read-only, so we don't either.
1103 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1104
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001105 // Traverse the name/value pairs and set the properties.
1106 int length = pairs->length();
1107 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001108 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001109 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001110 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001111
1112 // We have to declare a global const property. To capture we only
1113 // assign to it when evaluating the assignment for "const x =
1114 // <expr>" the initial value is the hole.
1115 bool is_const_property = value->IsTheHole();
1116
1117 if (value->IsUndefined() || is_const_property) {
1118 // Lookup the property in the global object, and don't set the
1119 // value of the variable if the property is already there.
1120 LookupResult lookup;
1121 global->Lookup(*name, &lookup);
1122 if (lookup.IsProperty()) {
1123 // Determine if the property is local by comparing the holder
1124 // against the global object. The information will be used to
1125 // avoid throwing re-declaration errors when declaring
1126 // variables or constants that exist in the prototype chain.
1127 bool is_local = (*global == lookup.holder());
1128 // Get the property attributes and determine if the property is
1129 // read-only.
1130 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1131 bool is_read_only = (attributes & READ_ONLY) != 0;
1132 if (lookup.type() == INTERCEPTOR) {
1133 // If the interceptor says the property is there, we
1134 // just return undefined without overwriting the property.
1135 // Otherwise, we continue to setting the property.
1136 if (attributes != ABSENT) {
1137 // Check if the existing property conflicts with regards to const.
1138 if (is_local && (is_read_only || is_const_property)) {
1139 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001140 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001141 };
1142 // The property already exists without conflicting: Go to
1143 // the next declaration.
1144 continue;
1145 }
1146 // Fall-through and introduce the absent property by using
1147 // SetProperty.
1148 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001149 // For const properties, we treat a callback with this name
1150 // even in the prototype as a conflicting declaration.
1151 if (is_const_property && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001152 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001153 }
1154 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001155 if (is_local && (is_read_only || is_const_property)) {
1156 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001157 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001158 }
1159 // The property already exists without conflicting: Go to
1160 // the next declaration.
1161 continue;
1162 }
1163 }
1164 } else {
1165 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001166 Handle<SharedFunctionInfo> shared =
1167 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001168 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001169 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1170 context,
1171 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001172 value = function;
1173 }
1174
1175 LookupResult lookup;
1176 global->LocalLookup(*name, &lookup);
1177
1178 PropertyAttributes attributes = is_const_property
1179 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1180 : base;
1181
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001182 // There's a local property that we need to overwrite because
1183 // we're either declaring a function or there's an interceptor
1184 // that claims the property is absent.
1185 //
1186 // Check for conflicting re-declarations. We cannot have
1187 // conflicting types in case of intercepted properties because
1188 // they are absent.
1189 if (lookup.IsProperty() &&
1190 (lookup.type() != INTERCEPTOR) &&
1191 (lookup.IsReadOnly() || is_const_property)) {
1192 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001193 return ThrowRedeclarationError(isolate, type, name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001194 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001195
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001196 // Safari does not allow the invocation of callback setters for
1197 // function declarations. To mimic this behavior, we do not allow
1198 // the invocation of setters for function values. This makes a
1199 // difference for global functions with the same names as event
1200 // handlers such as "function onload() {}". Firefox does call the
1201 // onload setter in those case and Safari does not. We follow
1202 // Safari for compatibility.
1203 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001204 // Do not change DONT_DELETE to false from true.
1205 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
1206 attributes = static_cast<PropertyAttributes>(
1207 attributes | (lookup.GetAttributes() & DONT_DELETE));
1208 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001209 RETURN_IF_EMPTY_HANDLE(isolate,
1210 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001211 name,
1212 value,
1213 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001214 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001215 RETURN_IF_EMPTY_HANDLE(isolate,
1216 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001217 name,
1218 value,
1219 attributes,
1220 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001221 }
1222 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001223
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001224 ASSERT(!isolate->has_pending_exception());
1225 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001226}
1227
1228
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001229RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001230 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001231 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001232
ager@chromium.org7c537e22008-10-16 08:43:32 +00001233 CONVERT_ARG_CHECKED(Context, context, 0);
1234 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001235 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001236 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001237 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001238
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001239 // Declarations are always done in a function or global context.
1240 context = Handle<Context>(context->declaration_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001241
1242 int index;
1243 PropertyAttributes attributes;
1244 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001245 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001246 context->Lookup(name, flags, &index, &attributes);
1247
1248 if (attributes != ABSENT) {
1249 // The name was declared before; check for conflicting
1250 // re-declarations: This is similar to the code in parser.cc in
1251 // the AstBuildingParser::Declare function.
1252 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1253 // Functions are not read-only.
1254 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1255 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001256 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001257 }
1258
1259 // Initialize it if necessary.
1260 if (*initial_value != NULL) {
1261 if (index >= 0) {
1262 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001263 // the function context or the arguments object.
1264 if (holder->IsContext()) {
1265 ASSERT(holder.is_identical_to(context));
1266 if (((attributes & READ_ONLY) == 0) ||
1267 context->get(index)->IsTheHole()) {
1268 context->set(index, *initial_value);
1269 }
1270 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001271 // The holder is an arguments object.
1272 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001273 Handle<Object> result = SetElement(arguments, index, initial_value,
1274 kNonStrictMode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001275 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001276 }
1277 } else {
1278 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001279 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001280 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001281 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001282 SetProperty(context_ext, name, initial_value,
1283 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001284 }
1285 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001286
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001287 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001288 // The property is not in the function context. It needs to be
1289 // "declared" in the function context's extension context, or in the
1290 // global context.
1291 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001292 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001293 // The function context's extension context exists - use it.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001294 context_ext = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001295 } else {
1296 // The function context's extension context does not exists - allocate
1297 // it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001298 context_ext = isolate->factory()->NewJSObject(
1299 isolate->context_extension_function());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001300 // And store it in the extension slot.
1301 context->set_extension(*context_ext);
1302 }
1303 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001304
ager@chromium.org7c537e22008-10-16 08:43:32 +00001305 // Declare the property by setting it to the initial value if provided,
1306 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1307 // constant declarations).
1308 ASSERT(!context_ext->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001309 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001310 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001311 // Declaring a const context slot is a conflicting declaration if
1312 // there is a callback with that name in a prototype. It is
1313 // allowed to introduce const variables in
1314 // JSContextExtensionObjects. They are treated specially in
1315 // SetProperty and no setters are invoked for those since they are
1316 // not real JSObjects.
1317 if (initial_value->IsTheHole() &&
1318 !context_ext->IsJSContextExtensionObject()) {
1319 LookupResult lookup;
1320 context_ext->Lookup(*name, &lookup);
1321 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001322 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001323 }
1324 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001325 RETURN_IF_EMPTY_HANDLE(isolate,
1326 SetProperty(context_ext, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001327 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001328 }
1329
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001330 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001331}
1332
1333
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001334RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001335 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001336 // args[0] == name
1337 // args[1] == strict_mode
1338 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001339
1340 // Determine if we need to assign to the variable if it already
1341 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001342 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1343 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001344
1345 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001346 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001347 RUNTIME_ASSERT(args[1]->IsSmi());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001348 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001349 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001350
1351 // According to ECMA-262, section 12.2, page 62, the property must
1352 // not be deletable.
1353 PropertyAttributes attributes = DONT_DELETE;
1354
1355 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001356 // there, there is a property with this name in the prototype chain.
1357 // We follow Safari and Firefox behavior and only set the property
1358 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001359 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001360 // Note that objects can have hidden prototypes, so we need to traverse
1361 // the whole chain of hidden prototypes to do a 'local' lookup.
1362 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001363 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001364 while (true) {
1365 real_holder->LocalLookup(*name, &lookup);
1366 if (lookup.IsProperty()) {
1367 // Determine if this is a redeclaration of something read-only.
1368 if (lookup.IsReadOnly()) {
1369 // If we found readonly property on one of hidden prototypes,
1370 // just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001371 if (real_holder != isolate->context()->global()) break;
1372 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001373 }
1374
1375 // Determine if this is a redeclaration of an intercepted read-only
1376 // property and figure out if the property exists at all.
1377 bool found = true;
1378 PropertyType type = lookup.type();
1379 if (type == INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001380 HandleScope handle_scope(isolate);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001381 Handle<JSObject> holder(real_holder);
1382 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1383 real_holder = *holder;
1384 if (intercepted == ABSENT) {
1385 // The interceptor claims the property isn't there. We need to
1386 // make sure to introduce it.
1387 found = false;
1388 } else if ((intercepted & READ_ONLY) != 0) {
1389 // The property is present, but read-only. Since we're trying to
1390 // overwrite it with a variable declaration we must throw a
1391 // re-declaration error. However if we found readonly property
1392 // on one of hidden prototypes, just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001393 if (real_holder != isolate->context()->global()) break;
1394 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001395 }
1396 }
1397
1398 if (found && !assign) {
1399 // The global property is there and we're not assigning any value
1400 // to it. Just return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001401 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001402 }
1403
1404 // Assign the value (or undefined) to the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001405 Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001406 return real_holder->SetProperty(
1407 &lookup, *name, value, attributes, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001408 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001409
1410 Object* proto = real_holder->GetPrototype();
1411 if (!proto->IsJSObject())
1412 break;
1413
1414 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1415 break;
1416
1417 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001418 }
1419
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001420 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001421 if (assign) {
1422 return global->SetProperty(*name, args[2], attributes, strict_mode);
1423 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001424 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001425}
1426
1427
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001428RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001429 // All constants are declared with an initial value. The name
1430 // of the constant is the first argument and the initial value
1431 // is the second.
1432 RUNTIME_ASSERT(args.length() == 2);
1433 CONVERT_ARG_CHECKED(String, name, 0);
1434 Handle<Object> value = args.at<Object>(1);
1435
1436 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001437 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001438
1439 // According to ECMA-262, section 12.2, page 62, the property must
1440 // not be deletable. Since it's a const, it must be READ_ONLY too.
1441 PropertyAttributes attributes =
1442 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1443
1444 // Lookup the property locally in the global object. If it isn't
1445 // there, we add the property and take special precautions to always
1446 // add it as a local property even in case of callbacks in the
1447 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001448 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001449 LookupResult lookup;
1450 global->LocalLookup(*name, &lookup);
1451 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001452 return global->SetLocalPropertyIgnoreAttributes(*name,
1453 *value,
1454 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001455 }
1456
1457 // Determine if this is a redeclaration of something not
1458 // read-only. In case the result is hidden behind an interceptor we
1459 // need to ask it for the property attributes.
1460 if (!lookup.IsReadOnly()) {
1461 if (lookup.type() != INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001462 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001463 }
1464
1465 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1466
1467 // Throw re-declaration error if the intercepted property is present
1468 // but not read-only.
1469 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
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 // Restore global object from context (in case of GC) and continue
1474 // with setting the value because the property is either absent or
1475 // read-only. We also have to do redo the lookup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001476 HandleScope handle_scope(isolate);
1477 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001478
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001479 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001480 // property through an interceptor and only do it if it's
1481 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001482 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001483 RETURN_IF_EMPTY_HANDLE(isolate,
1484 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001485 name,
1486 value,
1487 attributes,
1488 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001489 return *value;
1490 }
1491
1492 // Set the value, but only we're assigning the initial value to a
1493 // constant. For now, we determine this by checking if the
1494 // current value is the hole.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001495 // Strict mode handling not needed (const disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001496 PropertyType type = lookup.type();
1497 if (type == FIELD) {
1498 FixedArray* properties = global->properties();
1499 int index = lookup.GetFieldIndex();
1500 if (properties->get(index)->IsTheHole()) {
1501 properties->set(index, *value);
1502 }
1503 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001504 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1505 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001506 }
1507 } else {
1508 // Ignore re-initialization of constants that have already been
1509 // assigned a function value.
1510 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1511 }
1512
1513 // Use the set value as the result of the operation.
1514 return *value;
1515}
1516
1517
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001518RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001519 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001520 ASSERT(args.length() == 3);
1521
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001522 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001523 ASSERT(!value->IsTheHole());
1524 CONVERT_ARG_CHECKED(Context, context, 1);
1525 Handle<String> name(String::cast(args[2]));
1526
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001527 // Initializations are always done in a function or global context.
1528 context = Handle<Context>(context->declaration_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001529
1530 int index;
1531 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001532 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001533 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001534 context->Lookup(name, flags, &index, &attributes);
1535
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001536 // In most situations, the property introduced by the const
1537 // declaration should be present in the context extension object.
1538 // However, because declaration and initialization are separate, the
1539 // property might have been deleted (if it was introduced by eval)
1540 // before we reach the initialization point.
1541 //
1542 // Example:
1543 //
1544 // function f() { eval("delete x; const x;"); }
1545 //
1546 // In that case, the initialization behaves like a normal assignment
1547 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001548 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001549 if (holder->IsContext()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001550 // Property was found in a context. Perform the assignment if we
1551 // found some non-constant or an uninitialized constant.
1552 Handle<Context> context = Handle<Context>::cast(holder);
1553 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1554 context->set(index, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001555 }
1556 } else {
1557 // The holder is an arguments object.
1558 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001559 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001560 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001561 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001562 SetElement(arguments, index, value, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001563 }
1564 return *value;
1565 }
1566
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001567 // The property could not be found, we introduce it in the global
1568 // context.
1569 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001570 Handle<JSObject> global = Handle<JSObject>(
1571 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001572 // Strict mode not needed (const disallowed in strict mode).
1573 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001574 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001575 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001576 return *value;
1577 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001578
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001579 // The property was present in a context extension object.
1580 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001581
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001582 if (*context_ext == context->extension()) {
1583 // This is the property that was introduced by the const
1584 // declaration. Set it if it hasn't been set before. NOTE: We
1585 // cannot use GetProperty() to get the current value as it
1586 // 'unholes' the value.
1587 LookupResult lookup;
1588 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1589 ASSERT(lookup.IsProperty()); // the property was declared
1590 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1591
1592 PropertyType type = lookup.type();
1593 if (type == FIELD) {
1594 FixedArray* properties = context_ext->properties();
1595 int index = lookup.GetFieldIndex();
1596 if (properties->get(index)->IsTheHole()) {
1597 properties->set(index, *value);
1598 }
1599 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001600 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1601 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001602 }
1603 } else {
1604 // We should not reach here. Any real, named property should be
1605 // either a field or a dictionary slot.
1606 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001607 }
1608 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001609 // The property was found in a different context extension object.
1610 // Set it if it is not a read-only property.
1611 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001612 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001613 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001614 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001615 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001616 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001617 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001618
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001619 return *value;
1620}
1621
1622
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001623RUNTIME_FUNCTION(MaybeObject*,
1624 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001625 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001626 ASSERT(args.length() == 2);
1627 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001628 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001629 if (object->HasFastProperties()) {
1630 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1631 }
1632 return *object;
1633}
1634
1635
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001636RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001637 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001638 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001639 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1640 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001641 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001642 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001643 CONVERT_SMI_ARG_CHECKED(index, 2);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001644 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001645 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001646 RUNTIME_ASSERT(index >= 0);
1647 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001648 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001649 Handle<Object> result = RegExpImpl::Exec(regexp,
1650 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001651 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001652 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001653 if (result.is_null()) return Failure::Exception();
1654 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001655}
1656
1657
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001658RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001659 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001660 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001661 if (elements_count > JSArray::kMaxFastElementsLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001662 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001663 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001664 Object* new_object;
1665 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001666 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001667 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1668 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001669 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001670 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1671 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001672 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1673 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001674 {
1675 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001676 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001677 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001678 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001679 }
1680 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001681 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001682 array->set_elements(elements);
1683 array->set_length(Smi::FromInt(elements_count));
1684 // Write in-object properties after the length of the array.
1685 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1686 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1687 return array;
1688}
1689
1690
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001691RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001692 AssertNoAllocation no_alloc;
1693 ASSERT(args.length() == 5);
1694 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1695 CONVERT_CHECKED(String, source, args[1]);
1696
1697 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001698 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001699
1700 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001701 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001702
1703 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001704 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001705
1706 Map* map = regexp->map();
1707 Object* constructor = map->constructor();
1708 if (constructor->IsJSFunction() &&
1709 JSFunction::cast(constructor)->initial_map() == map) {
1710 // If we still have the original map, set in-object properties directly.
1711 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1712 // TODO(lrn): Consider skipping write barrier on booleans as well.
1713 // Both true and false should be in oldspace at all times.
1714 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1715 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1716 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1717 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1718 Smi::FromInt(0),
1719 SKIP_WRITE_BARRIER);
1720 return regexp;
1721 }
1722
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001723 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001724 PropertyAttributes final =
1725 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1726 PropertyAttributes writable =
1727 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001728 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001729 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001730 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001731 source,
1732 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001733 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001734 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001735 global,
1736 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001737 ASSERT(!result->IsFailure());
1738 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001739 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001740 ignoreCase,
1741 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001742 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001743 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001744 multiline,
1745 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001746 ASSERT(!result->IsFailure());
1747 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001748 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001749 Smi::FromInt(0),
1750 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001751 ASSERT(!result->IsFailure());
1752 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001753 return regexp;
1754}
1755
1756
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001757RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001758 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001759 ASSERT(args.length() == 1);
1760 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1761 // This is necessary to enable fast checks for absence of elements
1762 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001763 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001764 return Smi::FromInt(0);
1765}
1766
1767
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001768static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1769 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001770 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001771 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001772 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1773 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1774 Handle<JSFunction> optimized =
1775 isolate->factory()->NewFunction(key,
1776 JS_OBJECT_TYPE,
1777 JSObject::kHeaderSize,
1778 code,
1779 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001780 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001781 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001782 return optimized;
1783}
1784
1785
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001786RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001787 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001788 ASSERT(args.length() == 1);
1789 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1790
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001791 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1792 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1793 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1794 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1795 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1796 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1797 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001798
1799 return *holder;
1800}
1801
1802
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001803RUNTIME_FUNCTION(MaybeObject*, Runtime_GetGlobalReceiver) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001804 // Returns a real global receiver, not one of builtins object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001805 Context* global_context =
1806 isolate->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001807 return global_context->global()->global_receiver();
1808}
1809
1810
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001811RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001812 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001813 ASSERT(args.length() == 4);
1814 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001815 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001816 Handle<String> pattern = args.at<String>(2);
1817 Handle<String> flags = args.at<String>(3);
1818
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001819 // Get the RegExp function from the context in the literals array.
1820 // This is the RegExp function from the context in which the
1821 // function was created. We do not use the RegExp function from the
1822 // current global context because this might be the RegExp function
1823 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001824 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001825 Handle<JSFunction>(
1826 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001827 // Compute the regular expression literal.
1828 bool has_pending_exception;
1829 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001830 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1831 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001832 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001833 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001834 return Failure::Exception();
1835 }
1836 literals->set(index, *regexp);
1837 return *regexp;
1838}
1839
1840
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001841RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001842 NoHandleAllocation ha;
1843 ASSERT(args.length() == 1);
1844
1845 CONVERT_CHECKED(JSFunction, f, args[0]);
1846 return f->shared()->name();
1847}
1848
1849
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001850RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001851 NoHandleAllocation ha;
1852 ASSERT(args.length() == 2);
1853
1854 CONVERT_CHECKED(JSFunction, f, args[0]);
1855 CONVERT_CHECKED(String, name, args[1]);
1856 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001857 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001858}
1859
1860
whesse@chromium.org7b260152011-06-20 15:33:18 +00001861RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetBound) {
1862 HandleScope scope(isolate);
1863 ASSERT(args.length() == 1);
1864
1865 CONVERT_CHECKED(JSFunction, fun, args[0]);
1866 fun->shared()->set_bound(true);
1867 return isolate->heap()->undefined_value();
1868}
1869
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001870RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001871 NoHandleAllocation ha;
1872 ASSERT(args.length() == 1);
1873
1874 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001875 Object* obj = f->RemovePrototype();
1876 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001877
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001878 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001879}
1880
1881
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001882RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001883 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001884 ASSERT(args.length() == 1);
1885
1886 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001887 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1888 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001889
1890 return *GetScriptWrapper(Handle<Script>::cast(script));
1891}
1892
1893
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001894RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001895 NoHandleAllocation ha;
1896 ASSERT(args.length() == 1);
1897
1898 CONVERT_CHECKED(JSFunction, f, args[0]);
1899 return f->shared()->GetSourceCode();
1900}
1901
1902
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001903RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001904 NoHandleAllocation ha;
1905 ASSERT(args.length() == 1);
1906
1907 CONVERT_CHECKED(JSFunction, fun, args[0]);
1908 int pos = fun->shared()->start_position();
1909 return Smi::FromInt(pos);
1910}
1911
1912
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001913RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001914 ASSERT(args.length() == 2);
1915
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001916 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001917 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1918
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001919 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1920
1921 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001922 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001923}
1924
1925
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001926RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001927 NoHandleAllocation ha;
1928 ASSERT(args.length() == 2);
1929
1930 CONVERT_CHECKED(JSFunction, fun, args[0]);
1931 CONVERT_CHECKED(String, name, args[1]);
1932 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001933 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001934}
1935
1936
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001937RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001938 NoHandleAllocation ha;
1939 ASSERT(args.length() == 2);
1940
1941 CONVERT_CHECKED(JSFunction, fun, args[0]);
1942 CONVERT_CHECKED(Smi, length, args[1]);
1943 fun->shared()->set_length(length->value());
1944 return length;
1945}
1946
1947
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001948RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001949 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001950 ASSERT(args.length() == 2);
1951
1952 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001953 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001954 Object* obj;
1955 { MaybeObject* maybe_obj =
1956 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1957 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1958 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001959 return args[0]; // return TOS
1960}
1961
1962
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001963RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001964 NoHandleAllocation ha;
1965 ASSERT(args.length() == 1);
1966
1967 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001968 return f->shared()->IsApiFunction() ? isolate->heap()->true_value()
1969 : isolate->heap()->false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001970}
1971
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001972
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001973RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001974 NoHandleAllocation ha;
1975 ASSERT(args.length() == 1);
1976
1977 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001978 return f->IsBuiltin() ? isolate->heap()->true_value() :
1979 isolate->heap()->false_value();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001980}
1981
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001982
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001983RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001984 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001985 ASSERT(args.length() == 2);
1986
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001987 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001988 Handle<Object> code = args.at<Object>(1);
1989
1990 Handle<Context> context(target->context());
1991
1992 if (!code->IsNull()) {
1993 RUNTIME_ASSERT(code->IsJSFunction());
1994 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001995 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001996
1997 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001998 return Failure::Exception();
1999 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002000 // Since we don't store the source for this we should never
2001 // optimize this.
2002 shared->code()->set_optimizable(false);
2003
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002004 // Set the code, scope info, formal parameter count,
2005 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002006 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002007 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002008 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002009 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002010 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002011 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002012 // Set the source code of the target function to undefined.
2013 // SetCode is only used for built-in constructors like String,
2014 // Array, and Object, and some web code
2015 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002016 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002017 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002018 // Clear the optimization hints related to the compiled code as these are no
2019 // longer valid when the code is overwritten.
2020 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002021 context = Handle<Context>(fun->context());
2022
2023 // Make sure we get a fresh copy of the literal vector to avoid
2024 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002025 int number_of_literals = fun->NumberOfLiterals();
2026 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002027 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002028 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002029 // Insert the object, regexp and array functions in the literals
2030 // array prefix. These are the functions that will be used when
2031 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002032 literals->set(JSFunction::kLiteralGlobalContextIndex,
2033 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002034 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002035 // It's okay to skip the write barrier here because the literals
2036 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002037 target->set_literals(*literals, SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002038 target->set_next_function_link(isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002039 }
2040
2041 target->set_context(*context);
2042 return *target;
2043}
2044
2045
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002046RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002047 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002048 ASSERT(args.length() == 2);
2049 CONVERT_ARG_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002050 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002051 RUNTIME_ASSERT(num >= 0);
2052 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002053 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002054}
2055
2056
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002057MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2058 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002059 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002060 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002061 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002062 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002063 }
2064 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002065 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002066}
2067
2068
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002069RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002070 NoHandleAllocation ha;
2071 ASSERT(args.length() == 2);
2072
2073 CONVERT_CHECKED(String, subject, args[0]);
2074 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002075 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002076
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002077 uint32_t i = 0;
2078 if (index->IsSmi()) {
2079 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002080 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002081 i = value;
2082 } else {
2083 ASSERT(index->IsHeapNumber());
2084 double value = HeapNumber::cast(index)->value();
2085 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002086 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002087
2088 // Flatten the string. If someone wants to get a char at an index
2089 // in a cons string, it is likely that more indices will be
2090 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002091 Object* flat;
2092 { MaybeObject* maybe_flat = subject->TryFlatten();
2093 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2094 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002095 subject = String::cast(flat);
2096
2097 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002098 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002099 }
2100
2101 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002102}
2103
2104
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002105RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002106 NoHandleAllocation ha;
2107 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002108 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002109}
2110
lrn@chromium.org25156de2010-04-06 13:10:27 +00002111
2112class FixedArrayBuilder {
2113 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002114 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2115 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002116 length_(0) {
2117 // Require a non-zero initial size. Ensures that doubling the size to
2118 // extend the array will work.
2119 ASSERT(initial_capacity > 0);
2120 }
2121
2122 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2123 : array_(backing_store),
2124 length_(0) {
2125 // Require a non-zero initial size. Ensures that doubling the size to
2126 // extend the array will work.
2127 ASSERT(backing_store->length() > 0);
2128 }
2129
2130 bool HasCapacity(int elements) {
2131 int length = array_->length();
2132 int required_length = length_ + elements;
2133 return (length >= required_length);
2134 }
2135
2136 void EnsureCapacity(int elements) {
2137 int length = array_->length();
2138 int required_length = length_ + elements;
2139 if (length < required_length) {
2140 int new_length = length;
2141 do {
2142 new_length *= 2;
2143 } while (new_length < required_length);
2144 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002145 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002146 array_->CopyTo(0, *extended_array, 0, length_);
2147 array_ = extended_array;
2148 }
2149 }
2150
2151 void Add(Object* value) {
2152 ASSERT(length_ < capacity());
2153 array_->set(length_, value);
2154 length_++;
2155 }
2156
2157 void Add(Smi* value) {
2158 ASSERT(length_ < capacity());
2159 array_->set(length_, value);
2160 length_++;
2161 }
2162
2163 Handle<FixedArray> array() {
2164 return array_;
2165 }
2166
2167 int length() {
2168 return length_;
2169 }
2170
2171 int capacity() {
2172 return array_->length();
2173 }
2174
2175 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002176 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002177 result_array->set_length(Smi::FromInt(length_));
2178 return result_array;
2179 }
2180
2181 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2182 target_array->set_elements(*array_);
2183 target_array->set_length(Smi::FromInt(length_));
2184 return target_array;
2185 }
2186
2187 private:
2188 Handle<FixedArray> array_;
2189 int length_;
2190};
2191
2192
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002193// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002194const int kStringBuilderConcatHelperLengthBits = 11;
2195const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002196
2197template <typename schar>
2198static inline void StringBuilderConcatHelper(String*,
2199 schar*,
2200 FixedArray*,
2201 int);
2202
lrn@chromium.org25156de2010-04-06 13:10:27 +00002203typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2204 StringBuilderSubstringLength;
2205typedef BitField<int,
2206 kStringBuilderConcatHelperLengthBits,
2207 kStringBuilderConcatHelperPositionBits>
2208 StringBuilderSubstringPosition;
2209
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002210
2211class ReplacementStringBuilder {
2212 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002213 ReplacementStringBuilder(Heap* heap,
2214 Handle<String> subject,
2215 int estimated_part_count)
2216 : heap_(heap),
2217 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002218 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002219 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002220 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002221 // Require a non-zero initial size. Ensures that doubling the size to
2222 // extend the array will work.
2223 ASSERT(estimated_part_count > 0);
2224 }
2225
lrn@chromium.org25156de2010-04-06 13:10:27 +00002226 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2227 int from,
2228 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002229 ASSERT(from >= 0);
2230 int length = to - from;
2231 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002232 if (StringBuilderSubstringLength::is_valid(length) &&
2233 StringBuilderSubstringPosition::is_valid(from)) {
2234 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2235 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002236 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002237 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002238 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002239 builder->Add(Smi::FromInt(-length));
2240 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002241 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002242 }
2243
2244
2245 void EnsureCapacity(int elements) {
2246 array_builder_.EnsureCapacity(elements);
2247 }
2248
2249
2250 void AddSubjectSlice(int from, int to) {
2251 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002252 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002253 }
2254
2255
2256 void AddString(Handle<String> string) {
2257 int length = string->length();
2258 ASSERT(length > 0);
2259 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002260 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002261 is_ascii_ = false;
2262 }
2263 IncrementCharacterCount(length);
2264 }
2265
2266
2267 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002268 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002269 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002270 }
2271
2272 Handle<String> joined_string;
2273 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002274 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002275 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002276 char* char_buffer = seq->GetChars();
2277 StringBuilderConcatHelper(*subject_,
2278 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002279 *array_builder_.array(),
2280 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002281 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002282 } else {
2283 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002284 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002285 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002286 uc16* char_buffer = seq->GetChars();
2287 StringBuilderConcatHelper(*subject_,
2288 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002289 *array_builder_.array(),
2290 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002291 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002292 }
2293 return joined_string;
2294 }
2295
2296
2297 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002298 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002299 V8::FatalProcessOutOfMemory("String.replace result too large.");
2300 }
2301 character_count_ += by;
2302 }
2303
lrn@chromium.org25156de2010-04-06 13:10:27 +00002304 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002305 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002306 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002307
lrn@chromium.org25156de2010-04-06 13:10:27 +00002308 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002309 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2310 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002311 }
2312
2313
ager@chromium.org04921a82011-06-27 13:21:41 +00002314 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2315 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002316 }
2317
2318
2319 void AddElement(Object* element) {
2320 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002321 ASSERT(array_builder_.capacity() > array_builder_.length());
2322 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002323 }
2324
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002325 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002326 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002327 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002328 int character_count_;
2329 bool is_ascii_;
2330};
2331
2332
2333class CompiledReplacement {
2334 public:
2335 CompiledReplacement()
2336 : parts_(1), replacement_substrings_(0) {}
2337
2338 void Compile(Handle<String> replacement,
2339 int capture_count,
2340 int subject_length);
2341
2342 void Apply(ReplacementStringBuilder* builder,
2343 int match_from,
2344 int match_to,
2345 Handle<JSArray> last_match_info);
2346
2347 // Number of distinct parts of the replacement pattern.
2348 int parts() {
2349 return parts_.length();
2350 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002351
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002352 private:
2353 enum PartType {
2354 SUBJECT_PREFIX = 1,
2355 SUBJECT_SUFFIX,
2356 SUBJECT_CAPTURE,
2357 REPLACEMENT_SUBSTRING,
2358 REPLACEMENT_STRING,
2359
2360 NUMBER_OF_PART_TYPES
2361 };
2362
2363 struct ReplacementPart {
2364 static inline ReplacementPart SubjectMatch() {
2365 return ReplacementPart(SUBJECT_CAPTURE, 0);
2366 }
2367 static inline ReplacementPart SubjectCapture(int capture_index) {
2368 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2369 }
2370 static inline ReplacementPart SubjectPrefix() {
2371 return ReplacementPart(SUBJECT_PREFIX, 0);
2372 }
2373 static inline ReplacementPart SubjectSuffix(int subject_length) {
2374 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2375 }
2376 static inline ReplacementPart ReplacementString() {
2377 return ReplacementPart(REPLACEMENT_STRING, 0);
2378 }
2379 static inline ReplacementPart ReplacementSubString(int from, int to) {
2380 ASSERT(from >= 0);
2381 ASSERT(to > from);
2382 return ReplacementPart(-from, to);
2383 }
2384
2385 // If tag <= 0 then it is the negation of a start index of a substring of
2386 // the replacement pattern, otherwise it's a value from PartType.
2387 ReplacementPart(int tag, int data)
2388 : tag(tag), data(data) {
2389 // Must be non-positive or a PartType value.
2390 ASSERT(tag < NUMBER_OF_PART_TYPES);
2391 }
2392 // Either a value of PartType or a non-positive number that is
2393 // the negation of an index into the replacement string.
2394 int tag;
2395 // The data value's interpretation depends on the value of tag:
2396 // tag == SUBJECT_PREFIX ||
2397 // tag == SUBJECT_SUFFIX: data is unused.
2398 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2399 // tag == REPLACEMENT_SUBSTRING ||
2400 // tag == REPLACEMENT_STRING: data is index into array of substrings
2401 // of the replacement string.
2402 // tag <= 0: Temporary representation of the substring of the replacement
2403 // string ranging over -tag .. data.
2404 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2405 // substring objects.
2406 int data;
2407 };
2408
2409 template<typename Char>
2410 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2411 Vector<Char> characters,
2412 int capture_count,
2413 int subject_length) {
2414 int length = characters.length();
2415 int last = 0;
2416 for (int i = 0; i < length; i++) {
2417 Char c = characters[i];
2418 if (c == '$') {
2419 int next_index = i + 1;
2420 if (next_index == length) { // No next character!
2421 break;
2422 }
2423 Char c2 = characters[next_index];
2424 switch (c2) {
2425 case '$':
2426 if (i > last) {
2427 // There is a substring before. Include the first "$".
2428 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2429 last = next_index + 1; // Continue after the second "$".
2430 } else {
2431 // Let the next substring start with the second "$".
2432 last = next_index;
2433 }
2434 i = next_index;
2435 break;
2436 case '`':
2437 if (i > last) {
2438 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2439 }
2440 parts->Add(ReplacementPart::SubjectPrefix());
2441 i = next_index;
2442 last = i + 1;
2443 break;
2444 case '\'':
2445 if (i > last) {
2446 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2447 }
2448 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
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::SubjectMatch());
2457 i = next_index;
2458 last = i + 1;
2459 break;
2460 case '0':
2461 case '1':
2462 case '2':
2463 case '3':
2464 case '4':
2465 case '5':
2466 case '6':
2467 case '7':
2468 case '8':
2469 case '9': {
2470 int capture_ref = c2 - '0';
2471 if (capture_ref > capture_count) {
2472 i = next_index;
2473 continue;
2474 }
2475 int second_digit_index = next_index + 1;
2476 if (second_digit_index < length) {
2477 // Peek ahead to see if we have two digits.
2478 Char c3 = characters[second_digit_index];
2479 if ('0' <= c3 && c3 <= '9') { // Double digits.
2480 int double_digit_ref = capture_ref * 10 + c3 - '0';
2481 if (double_digit_ref <= capture_count) {
2482 next_index = second_digit_index;
2483 capture_ref = double_digit_ref;
2484 }
2485 }
2486 }
2487 if (capture_ref > 0) {
2488 if (i > last) {
2489 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2490 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002491 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002492 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2493 last = next_index + 1;
2494 }
2495 i = next_index;
2496 break;
2497 }
2498 default:
2499 i = next_index;
2500 break;
2501 }
2502 }
2503 }
2504 if (length > last) {
2505 if (last == 0) {
2506 parts->Add(ReplacementPart::ReplacementString());
2507 } else {
2508 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2509 }
2510 }
2511 }
2512
2513 ZoneList<ReplacementPart> parts_;
2514 ZoneList<Handle<String> > replacement_substrings_;
2515};
2516
2517
2518void CompiledReplacement::Compile(Handle<String> replacement,
2519 int capture_count,
2520 int subject_length) {
2521 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002522 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002523 AssertNoAllocation no_alloc;
2524 ParseReplacementPattern(&parts_,
2525 replacement->ToAsciiVector(),
2526 capture_count,
2527 subject_length);
2528 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002529 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002530 AssertNoAllocation no_alloc;
2531
2532 ParseReplacementPattern(&parts_,
2533 replacement->ToUC16Vector(),
2534 capture_count,
2535 subject_length);
2536 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002537 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002538 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002539 int substring_index = 0;
2540 for (int i = 0, n = parts_.length(); i < n; i++) {
2541 int tag = parts_[i].tag;
2542 if (tag <= 0) { // A replacement string slice.
2543 int from = -tag;
2544 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002545 replacement_substrings_.Add(
2546 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002547 parts_[i].tag = REPLACEMENT_SUBSTRING;
2548 parts_[i].data = substring_index;
2549 substring_index++;
2550 } else if (tag == REPLACEMENT_STRING) {
2551 replacement_substrings_.Add(replacement);
2552 parts_[i].data = substring_index;
2553 substring_index++;
2554 }
2555 }
2556}
2557
2558
2559void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2560 int match_from,
2561 int match_to,
2562 Handle<JSArray> last_match_info) {
2563 for (int i = 0, n = parts_.length(); i < n; i++) {
2564 ReplacementPart part = parts_[i];
2565 switch (part.tag) {
2566 case SUBJECT_PREFIX:
2567 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2568 break;
2569 case SUBJECT_SUFFIX: {
2570 int subject_length = part.data;
2571 if (match_to < subject_length) {
2572 builder->AddSubjectSlice(match_to, subject_length);
2573 }
2574 break;
2575 }
2576 case SUBJECT_CAPTURE: {
2577 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002578 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002579 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2580 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2581 if (from >= 0 && to > from) {
2582 builder->AddSubjectSlice(from, to);
2583 }
2584 break;
2585 }
2586 case REPLACEMENT_SUBSTRING:
2587 case REPLACEMENT_STRING:
2588 builder->AddString(replacement_substrings_[part.data]);
2589 break;
2590 default:
2591 UNREACHABLE();
2592 }
2593 }
2594}
2595
2596
2597
lrn@chromium.org303ada72010-10-27 09:33:13 +00002598MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002599 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002600 String* subject,
2601 JSRegExp* regexp,
2602 String* replacement,
2603 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002604 ASSERT(subject->IsFlat());
2605 ASSERT(replacement->IsFlat());
2606
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002607 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002608
2609 int length = subject->length();
2610 Handle<String> subject_handle(subject);
2611 Handle<JSRegExp> regexp_handle(regexp);
2612 Handle<String> replacement_handle(replacement);
2613 Handle<JSArray> last_match_info_handle(last_match_info);
2614 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2615 subject_handle,
2616 0,
2617 last_match_info_handle);
2618 if (match.is_null()) {
2619 return Failure::Exception();
2620 }
2621 if (match->IsNull()) {
2622 return *subject_handle;
2623 }
2624
2625 int capture_count = regexp_handle->CaptureCount();
2626
2627 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002628 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002629 CompiledReplacement compiled_replacement;
2630 compiled_replacement.Compile(replacement_handle,
2631 capture_count,
2632 length);
2633
2634 bool is_global = regexp_handle->GetFlags().is_global();
2635
2636 // Guessing the number of parts that the final result string is built
2637 // from. Global regexps can match any number of times, so we guess
2638 // conservatively.
2639 int expected_parts =
2640 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002641 ReplacementStringBuilder builder(isolate->heap(),
2642 subject_handle,
2643 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002644
2645 // Index of end of last match.
2646 int prev = 0;
2647
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002648 // Number of parts added by compiled replacement plus preceeding
2649 // string and possibly suffix after last match. It is possible for
2650 // all components to use two elements when encoded as two smis.
2651 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002652 bool matched = true;
2653 do {
2654 ASSERT(last_match_info_handle->HasFastElements());
2655 // Increase the capacity of the builder before entering local handle-scope,
2656 // so its internal buffer can safely allocate a new handle if it grows.
2657 builder.EnsureCapacity(parts_added_per_loop);
2658
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002659 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002660 int start, end;
2661 {
2662 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002663 FixedArray* match_info_array =
2664 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002665
2666 ASSERT_EQ(capture_count * 2 + 2,
2667 RegExpImpl::GetLastCaptureCount(match_info_array));
2668 start = RegExpImpl::GetCapture(match_info_array, 0);
2669 end = RegExpImpl::GetCapture(match_info_array, 1);
2670 }
2671
2672 if (prev < start) {
2673 builder.AddSubjectSlice(prev, start);
2674 }
2675 compiled_replacement.Apply(&builder,
2676 start,
2677 end,
2678 last_match_info_handle);
2679 prev = end;
2680
2681 // Only continue checking for global regexps.
2682 if (!is_global) break;
2683
2684 // Continue from where the match ended, unless it was an empty match.
2685 int next = end;
2686 if (start == end) {
2687 next = end + 1;
2688 if (next > length) break;
2689 }
2690
2691 match = RegExpImpl::Exec(regexp_handle,
2692 subject_handle,
2693 next,
2694 last_match_info_handle);
2695 if (match.is_null()) {
2696 return Failure::Exception();
2697 }
2698 matched = !match->IsNull();
2699 } while (matched);
2700
2701 if (prev < length) {
2702 builder.AddSubjectSlice(prev, length);
2703 }
2704
2705 return *(builder.ToString());
2706}
2707
2708
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002709template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002710MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002711 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002712 String* subject,
2713 JSRegExp* regexp,
2714 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002715 ASSERT(subject->IsFlat());
2716
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002717 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002718
2719 Handle<String> subject_handle(subject);
2720 Handle<JSRegExp> regexp_handle(regexp);
2721 Handle<JSArray> last_match_info_handle(last_match_info);
2722 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2723 subject_handle,
2724 0,
2725 last_match_info_handle);
2726 if (match.is_null()) return Failure::Exception();
2727 if (match->IsNull()) return *subject_handle;
2728
2729 ASSERT(last_match_info_handle->HasFastElements());
2730
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002731 int start, end;
2732 {
2733 AssertNoAllocation match_info_array_is_not_in_a_handle;
2734 FixedArray* match_info_array =
2735 FixedArray::cast(last_match_info_handle->elements());
2736
2737 start = RegExpImpl::GetCapture(match_info_array, 0);
2738 end = RegExpImpl::GetCapture(match_info_array, 1);
2739 }
2740
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002741 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002742 int new_length = length - (end - start);
2743 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002744 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002745 }
2746 Handle<ResultSeqString> answer;
2747 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002748 answer = Handle<ResultSeqString>::cast(
2749 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002750 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002751 answer = Handle<ResultSeqString>::cast(
2752 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002753 }
2754
2755 // If the regexp isn't global, only match once.
2756 if (!regexp_handle->GetFlags().is_global()) {
2757 if (start > 0) {
2758 String::WriteToFlat(*subject_handle,
2759 answer->GetChars(),
2760 0,
2761 start);
2762 }
2763 if (end < length) {
2764 String::WriteToFlat(*subject_handle,
2765 answer->GetChars() + start,
2766 end,
2767 length);
2768 }
2769 return *answer;
2770 }
2771
2772 int prev = 0; // Index of end of last match.
2773 int next = 0; // Start of next search (prev unless last match was empty).
2774 int position = 0;
2775
2776 do {
2777 if (prev < start) {
2778 // Add substring subject[prev;start] to answer string.
2779 String::WriteToFlat(*subject_handle,
2780 answer->GetChars() + position,
2781 prev,
2782 start);
2783 position += start - prev;
2784 }
2785 prev = end;
2786 next = end;
2787 // Continue from where the match ended, unless it was an empty match.
2788 if (start == end) {
2789 next++;
2790 if (next > length) break;
2791 }
2792 match = RegExpImpl::Exec(regexp_handle,
2793 subject_handle,
2794 next,
2795 last_match_info_handle);
2796 if (match.is_null()) return Failure::Exception();
2797 if (match->IsNull()) break;
2798
2799 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002800 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002801 {
2802 AssertNoAllocation match_info_array_is_not_in_a_handle;
2803 FixedArray* match_info_array =
2804 FixedArray::cast(last_match_info_handle->elements());
2805 start = RegExpImpl::GetCapture(match_info_array, 0);
2806 end = RegExpImpl::GetCapture(match_info_array, 1);
2807 }
2808 } while (true);
2809
2810 if (prev < length) {
2811 // Add substring subject[prev;length] to answer string.
2812 String::WriteToFlat(*subject_handle,
2813 answer->GetChars() + position,
2814 prev,
2815 length);
2816 position += length - prev;
2817 }
2818
2819 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002820 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002821 }
2822
2823 // Shorten string and fill
2824 int string_size = ResultSeqString::SizeFor(position);
2825 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2826 int delta = allocated_string_size - string_size;
2827
2828 answer->set_length(position);
2829 if (delta == 0) return *answer;
2830
2831 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002832 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002833
2834 return *answer;
2835}
2836
2837
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002838RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002839 ASSERT(args.length() == 4);
2840
2841 CONVERT_CHECKED(String, subject, args[0]);
2842 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002843 Object* flat_subject;
2844 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2845 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2846 return maybe_flat_subject;
2847 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002848 }
2849 subject = String::cast(flat_subject);
2850 }
2851
2852 CONVERT_CHECKED(String, replacement, args[2]);
2853 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002854 Object* flat_replacement;
2855 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2856 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2857 return maybe_flat_replacement;
2858 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002859 }
2860 replacement = String::cast(flat_replacement);
2861 }
2862
2863 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2864 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2865
2866 ASSERT(last_match_info->HasFastElements());
2867
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002868 if (replacement->length() == 0) {
2869 if (subject->HasOnlyAsciiChars()) {
2870 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002871 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002872 } else {
2873 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002874 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002875 }
2876 }
2877
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002878 return StringReplaceRegExpWithString(isolate,
2879 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002880 regexp,
2881 replacement,
2882 last_match_info);
2883}
2884
2885
ager@chromium.org7c537e22008-10-16 08:43:32 +00002886// Perform string match of pattern on subject, starting at start index.
2887// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002888// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002889int Runtime::StringMatch(Isolate* isolate,
2890 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00002891 Handle<String> pat,
2892 int start_index) {
2893 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002894 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002895
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002896 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002897 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002898
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002899 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002900 if (start_index + pattern_length > subject_length) return -1;
2901
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002902 if (!sub->IsFlat()) FlattenString(sub);
2903 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002904
ager@chromium.org7c537e22008-10-16 08:43:32 +00002905 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002906 // Extract flattened substrings of cons strings before determining asciiness.
2907 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002908 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002909 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002910 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002911
ager@chromium.org7c537e22008-10-16 08:43:32 +00002912 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002913 if (seq_pat->IsAsciiRepresentation()) {
2914 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2915 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002916 return SearchString(isolate,
2917 seq_sub->ToAsciiVector(),
2918 pat_vector,
2919 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002920 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002921 return SearchString(isolate,
2922 seq_sub->ToUC16Vector(),
2923 pat_vector,
2924 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002925 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002926 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2927 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002928 return SearchString(isolate,
2929 seq_sub->ToAsciiVector(),
2930 pat_vector,
2931 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002932 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002933 return SearchString(isolate,
2934 seq_sub->ToUC16Vector(),
2935 pat_vector,
2936 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002937}
2938
2939
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002940RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002941 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002942 ASSERT(args.length() == 3);
2943
ager@chromium.org7c537e22008-10-16 08:43:32 +00002944 CONVERT_ARG_CHECKED(String, sub, 0);
2945 CONVERT_ARG_CHECKED(String, pat, 1);
2946
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002947 Object* index = args[2];
2948 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002949 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002950
ager@chromium.org870a0b62008-11-04 11:43:05 +00002951 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002952 int position =
2953 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002954 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002955}
2956
2957
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002958template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002959static int StringMatchBackwards(Vector<const schar> subject,
2960 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002961 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002962 int pattern_length = pattern.length();
2963 ASSERT(pattern_length >= 1);
2964 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002965
2966 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002967 for (int i = 0; i < pattern_length; i++) {
2968 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002969 if (c > String::kMaxAsciiCharCode) {
2970 return -1;
2971 }
2972 }
2973 }
2974
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002975 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002976 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002977 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002978 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002979 while (j < pattern_length) {
2980 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002981 break;
2982 }
2983 j++;
2984 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002985 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002986 return i;
2987 }
2988 }
2989 return -1;
2990}
2991
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002992RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002993 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002994 ASSERT(args.length() == 3);
2995
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002996 CONVERT_ARG_CHECKED(String, sub, 0);
2997 CONVERT_ARG_CHECKED(String, pat, 1);
2998
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002999 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003000 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003001 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003002
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003003 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003004 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003005
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003006 if (start_index + pat_length > sub_length) {
3007 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003008 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003009
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003010 if (pat_length == 0) {
3011 return Smi::FromInt(start_index);
3012 }
3013
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003014 if (!sub->IsFlat()) FlattenString(sub);
3015 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003016
3017 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3018
3019 int position = -1;
3020
3021 if (pat->IsAsciiRepresentation()) {
3022 Vector<const char> pat_vector = pat->ToAsciiVector();
3023 if (sub->IsAsciiRepresentation()) {
3024 position = StringMatchBackwards(sub->ToAsciiVector(),
3025 pat_vector,
3026 start_index);
3027 } else {
3028 position = StringMatchBackwards(sub->ToUC16Vector(),
3029 pat_vector,
3030 start_index);
3031 }
3032 } else {
3033 Vector<const uc16> pat_vector = pat->ToUC16Vector();
3034 if (sub->IsAsciiRepresentation()) {
3035 position = StringMatchBackwards(sub->ToAsciiVector(),
3036 pat_vector,
3037 start_index);
3038 } else {
3039 position = StringMatchBackwards(sub->ToUC16Vector(),
3040 pat_vector,
3041 start_index);
3042 }
3043 }
3044
3045 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003046}
3047
3048
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003049RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003050 NoHandleAllocation ha;
3051 ASSERT(args.length() == 2);
3052
3053 CONVERT_CHECKED(String, str1, args[0]);
3054 CONVERT_CHECKED(String, str2, args[1]);
3055
3056 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003057 int str1_length = str1->length();
3058 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003059
3060 // Decide trivial cases without flattening.
3061 if (str1_length == 0) {
3062 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3063 return Smi::FromInt(-str2_length);
3064 } else {
3065 if (str2_length == 0) return Smi::FromInt(str1_length);
3066 }
3067
3068 int end = str1_length < str2_length ? str1_length : str2_length;
3069
3070 // No need to flatten if we are going to find the answer on the first
3071 // character. At this point we know there is at least one character
3072 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003073 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003074 if (d != 0) return Smi::FromInt(d);
3075
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003076 str1->TryFlatten();
3077 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003078
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003079 StringInputBuffer& buf1 =
3080 *isolate->runtime_state()->string_locale_compare_buf1();
3081 StringInputBuffer& buf2 =
3082 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003083
3084 buf1.Reset(str1);
3085 buf2.Reset(str2);
3086
3087 for (int i = 0; i < end; i++) {
3088 uint16_t char1 = buf1.GetNext();
3089 uint16_t char2 = buf2.GetNext();
3090 if (char1 != char2) return Smi::FromInt(char1 - char2);
3091 }
3092
3093 return Smi::FromInt(str1_length - str2_length);
3094}
3095
3096
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003097RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003098 NoHandleAllocation ha;
3099 ASSERT(args.length() == 3);
3100
3101 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003102 int start, end;
3103 // We have a fast integer-only case here to avoid a conversion to double in
3104 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003105 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3106 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3107 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3108 start = from_number;
3109 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003110 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003111 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3112 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003113 start = FastD2I(from_number);
3114 end = FastD2I(to_number);
3115 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003116 RUNTIME_ASSERT(end >= start);
3117 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003118 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003119 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003120 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003121}
3122
3123
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003124RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003125 ASSERT_EQ(3, args.length());
3126
3127 CONVERT_ARG_CHECKED(String, subject, 0);
3128 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3129 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3130 HandleScope handles;
3131
3132 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3133
3134 if (match.is_null()) {
3135 return Failure::Exception();
3136 }
3137 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003138 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003139 }
3140 int length = subject->length();
3141
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003142 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003143 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003144 int start;
3145 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003146 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003147 {
3148 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003149 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003150 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3151 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3152 }
3153 offsets.Add(start);
3154 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003155 if (start == end) if (++end > length) break;
3156 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003157 if (match.is_null()) {
3158 return Failure::Exception();
3159 }
3160 } while (!match->IsNull());
3161 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003162 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003163 Handle<String> substring = isolate->factory()->
3164 NewSubString(subject, offsets.at(0), offsets.at(1));
3165 elements->set(0, *substring);
3166 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003167 int from = offsets.at(i * 2);
3168 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003169 Handle<String> substring = isolate->factory()->
3170 NewProperSubString(subject, from, to);
3171 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003172 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003173 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003174 result->set_length(Smi::FromInt(matches));
3175 return *result;
3176}
3177
3178
lrn@chromium.org25156de2010-04-06 13:10:27 +00003179// Two smis before and after the match, for very long strings.
3180const int kMaxBuilderEntriesPerRegExpMatch = 5;
3181
3182
3183static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3184 Handle<JSArray> last_match_info,
3185 int match_start,
3186 int match_end) {
3187 // Fill last_match_info with a single capture.
3188 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3189 AssertNoAllocation no_gc;
3190 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3191 RegExpImpl::SetLastCaptureCount(elements, 2);
3192 RegExpImpl::SetLastInput(elements, *subject);
3193 RegExpImpl::SetLastSubject(elements, *subject);
3194 RegExpImpl::SetCapture(elements, 0, match_start);
3195 RegExpImpl::SetCapture(elements, 1, match_end);
3196}
3197
3198
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003199template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003200static bool SearchStringMultiple(Isolate* isolate,
3201 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003202 Vector<const PatternChar> pattern,
3203 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003204 FixedArrayBuilder* builder,
3205 int* match_pos) {
3206 int pos = *match_pos;
3207 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003208 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003209 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003210 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003211 while (pos <= max_search_start) {
3212 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3213 *match_pos = pos;
3214 return false;
3215 }
3216 // Position of end of previous match.
3217 int match_end = pos + pattern_length;
3218 int new_pos = search.Search(subject, match_end);
3219 if (new_pos >= 0) {
3220 // A match.
3221 if (new_pos > match_end) {
3222 ReplacementStringBuilder::AddSubjectSlice(builder,
3223 match_end,
3224 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003225 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003226 pos = new_pos;
3227 builder->Add(pattern_string);
3228 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003229 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003230 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003231 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003232
lrn@chromium.org25156de2010-04-06 13:10:27 +00003233 if (pos < max_search_start) {
3234 ReplacementStringBuilder::AddSubjectSlice(builder,
3235 pos + pattern_length,
3236 subject_length);
3237 }
3238 *match_pos = pos;
3239 return true;
3240}
3241
3242
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003243static bool SearchStringMultiple(Isolate* isolate,
3244 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003245 Handle<String> pattern,
3246 Handle<JSArray> last_match_info,
3247 FixedArrayBuilder* builder) {
3248 ASSERT(subject->IsFlat());
3249 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003250
3251 // Treating as if a previous match was before first character.
3252 int match_pos = -pattern->length();
3253
3254 for (;;) { // Break when search complete.
3255 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3256 AssertNoAllocation no_gc;
3257 if (subject->IsAsciiRepresentation()) {
3258 Vector<const char> subject_vector = subject->ToAsciiVector();
3259 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003260 if (SearchStringMultiple(isolate,
3261 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003262 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003263 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003264 builder,
3265 &match_pos)) break;
3266 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003267 if (SearchStringMultiple(isolate,
3268 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003269 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003270 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003271 builder,
3272 &match_pos)) break;
3273 }
3274 } else {
3275 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3276 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003277 if (SearchStringMultiple(isolate,
3278 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003279 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003280 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003281 builder,
3282 &match_pos)) break;
3283 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003284 if (SearchStringMultiple(isolate,
3285 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003286 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003287 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003288 builder,
3289 &match_pos)) break;
3290 }
3291 }
3292 }
3293
3294 if (match_pos >= 0) {
3295 SetLastMatchInfoNoCaptures(subject,
3296 last_match_info,
3297 match_pos,
3298 match_pos + pattern->length());
3299 return true;
3300 }
3301 return false; // No matches at all.
3302}
3303
3304
3305static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003306 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003307 Handle<String> subject,
3308 Handle<JSRegExp> regexp,
3309 Handle<JSArray> last_match_array,
3310 FixedArrayBuilder* builder) {
3311 ASSERT(subject->IsFlat());
3312 int match_start = -1;
3313 int match_end = 0;
3314 int pos = 0;
3315 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3316 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3317
3318 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003319 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003320 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003321 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003322
3323 for (;;) { // Break on failure, return on exception.
3324 RegExpImpl::IrregexpResult result =
3325 RegExpImpl::IrregexpExecOnce(regexp,
3326 subject,
3327 pos,
3328 register_vector);
3329 if (result == RegExpImpl::RE_SUCCESS) {
3330 match_start = register_vector[0];
3331 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3332 if (match_end < match_start) {
3333 ReplacementStringBuilder::AddSubjectSlice(builder,
3334 match_end,
3335 match_start);
3336 }
3337 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003338 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003339 if (!first) {
3340 builder->Add(*isolate->factory()->NewProperSubString(subject,
3341 match_start,
3342 match_end));
3343 } else {
3344 builder->Add(*isolate->factory()->NewSubString(subject,
3345 match_start,
3346 match_end));
3347 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003348 if (match_start != match_end) {
3349 pos = match_end;
3350 } else {
3351 pos = match_end + 1;
3352 if (pos > subject_length) break;
3353 }
3354 } else if (result == RegExpImpl::RE_FAILURE) {
3355 break;
3356 } else {
3357 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3358 return result;
3359 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003360 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003361 }
3362
3363 if (match_start >= 0) {
3364 if (match_end < subject_length) {
3365 ReplacementStringBuilder::AddSubjectSlice(builder,
3366 match_end,
3367 subject_length);
3368 }
3369 SetLastMatchInfoNoCaptures(subject,
3370 last_match_array,
3371 match_start,
3372 match_end);
3373 return RegExpImpl::RE_SUCCESS;
3374 } else {
3375 return RegExpImpl::RE_FAILURE; // No matches at all.
3376 }
3377}
3378
3379
3380static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003381 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003382 Handle<String> subject,
3383 Handle<JSRegExp> regexp,
3384 Handle<JSArray> last_match_array,
3385 FixedArrayBuilder* builder) {
3386
3387 ASSERT(subject->IsFlat());
3388 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3389 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3390
3391 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003392 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003393
3394 RegExpImpl::IrregexpResult result =
3395 RegExpImpl::IrregexpExecOnce(regexp,
3396 subject,
3397 0,
3398 register_vector);
3399
3400 int capture_count = regexp->CaptureCount();
3401 int subject_length = subject->length();
3402
3403 // Position to search from.
3404 int pos = 0;
3405 // End of previous match. Differs from pos if match was empty.
3406 int match_end = 0;
3407 if (result == RegExpImpl::RE_SUCCESS) {
3408 // Need to keep a copy of the previous match for creating last_match_info
3409 // at the end, so we have two vectors that we swap between.
3410 OffsetsVector registers2(required_registers);
3411 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003412 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003413 do {
3414 int match_start = register_vector[0];
3415 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3416 if (match_end < match_start) {
3417 ReplacementStringBuilder::AddSubjectSlice(builder,
3418 match_end,
3419 match_start);
3420 }
3421 match_end = register_vector[1];
3422
3423 {
3424 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003425 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003426 // Arguments array to replace function is match, captures, index and
3427 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003428 Handle<FixedArray> elements =
3429 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003430 Handle<String> match;
3431 if (!first) {
3432 match = isolate->factory()->NewProperSubString(subject,
3433 match_start,
3434 match_end);
3435 } else {
3436 match = isolate->factory()->NewSubString(subject,
3437 match_start,
3438 match_end);
3439 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003440 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003441 for (int i = 1; i <= capture_count; i++) {
3442 int start = register_vector[i * 2];
3443 if (start >= 0) {
3444 int end = register_vector[i * 2 + 1];
3445 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003446 Handle<String> substring;
3447 if (!first) {
3448 substring = isolate->factory()->NewProperSubString(subject,
3449 start,
3450 end);
3451 } else {
3452 substring = isolate->factory()->NewSubString(subject, start, end);
3453 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003454 elements->set(i, *substring);
3455 } else {
3456 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003457 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003458 }
3459 }
3460 elements->set(capture_count + 1, Smi::FromInt(match_start));
3461 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003462 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003463 }
3464 // Swap register vectors, so the last successful match is in
3465 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003466 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003467 prev_register_vector = register_vector;
3468 register_vector = tmp;
3469
3470 if (match_end > match_start) {
3471 pos = match_end;
3472 } else {
3473 pos = match_end + 1;
3474 if (pos > subject_length) {
3475 break;
3476 }
3477 }
3478
3479 result = RegExpImpl::IrregexpExecOnce(regexp,
3480 subject,
3481 pos,
3482 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003483 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003484 } while (result == RegExpImpl::RE_SUCCESS);
3485
3486 if (result != RegExpImpl::RE_EXCEPTION) {
3487 // Finished matching, with at least one match.
3488 if (match_end < subject_length) {
3489 ReplacementStringBuilder::AddSubjectSlice(builder,
3490 match_end,
3491 subject_length);
3492 }
3493
3494 int last_match_capture_count = (capture_count + 1) * 2;
3495 int last_match_array_size =
3496 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3497 last_match_array->EnsureSize(last_match_array_size);
3498 AssertNoAllocation no_gc;
3499 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3500 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3501 RegExpImpl::SetLastSubject(elements, *subject);
3502 RegExpImpl::SetLastInput(elements, *subject);
3503 for (int i = 0; i < last_match_capture_count; i++) {
3504 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3505 }
3506 return RegExpImpl::RE_SUCCESS;
3507 }
3508 }
3509 // No matches at all, return failure or exception result directly.
3510 return result;
3511}
3512
3513
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003514RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003515 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003516 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003517
3518 CONVERT_ARG_CHECKED(String, subject, 1);
3519 if (!subject->IsFlat()) { FlattenString(subject); }
3520 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3521 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3522 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3523
3524 ASSERT(last_match_info->HasFastElements());
3525 ASSERT(regexp->GetFlags().is_global());
3526 Handle<FixedArray> result_elements;
3527 if (result_array->HasFastElements()) {
3528 result_elements =
3529 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003530 }
3531 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003532 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003533 }
3534 FixedArrayBuilder builder(result_elements);
3535
3536 if (regexp->TypeTag() == JSRegExp::ATOM) {
3537 Handle<String> pattern(
3538 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003539 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003540 if (SearchStringMultiple(isolate, subject, pattern,
3541 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003542 return *builder.ToJSArray(result_array);
3543 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003544 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003545 }
3546
3547 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3548
3549 RegExpImpl::IrregexpResult result;
3550 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003551 result = SearchRegExpNoCaptureMultiple(isolate,
3552 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003553 regexp,
3554 last_match_info,
3555 &builder);
3556 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003557 result = SearchRegExpMultiple(isolate,
3558 subject,
3559 regexp,
3560 last_match_info,
3561 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003562 }
3563 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003564 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003565 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3566 return Failure::Exception();
3567}
3568
3569
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003570RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003571 NoHandleAllocation ha;
3572 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003573 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003574 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003575
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003576 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003577 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003578 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003579 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003580 // Character array used for conversion.
3581 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003582 return isolate->heap()->
3583 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003584 }
3585 }
3586
3587 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003588 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003589 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003590 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003591 }
3592 if (isinf(value)) {
3593 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003594 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003595 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003596 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003597 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003598 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003599 MaybeObject* result =
3600 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003601 DeleteArray(str);
3602 return result;
3603}
3604
3605
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003606RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003607 NoHandleAllocation ha;
3608 ASSERT(args.length() == 2);
3609
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003610 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003611 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003612 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003613 }
3614 if (isinf(value)) {
3615 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003616 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003617 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003618 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003619 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003620 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003621 int f = FastD2I(f_number);
3622 RUNTIME_ASSERT(f >= 0);
3623 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003624 MaybeObject* res =
3625 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003626 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003627 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003628}
3629
3630
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003631RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003632 NoHandleAllocation ha;
3633 ASSERT(args.length() == 2);
3634
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003635 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003636 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003637 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003638 }
3639 if (isinf(value)) {
3640 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003641 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003642 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003643 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003644 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003645 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003646 int f = FastD2I(f_number);
3647 RUNTIME_ASSERT(f >= -1 && f <= 20);
3648 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003649 MaybeObject* res =
3650 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003651 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003652 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003653}
3654
3655
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003656RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003657 NoHandleAllocation ha;
3658 ASSERT(args.length() == 2);
3659
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003660 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003661 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003662 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003663 }
3664 if (isinf(value)) {
3665 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003666 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003667 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003668 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003669 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003670 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003671 int f = FastD2I(f_number);
3672 RUNTIME_ASSERT(f >= 1 && f <= 21);
3673 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003674 MaybeObject* res =
3675 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003676 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003677 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003678}
3679
3680
3681// Returns a single character string where first character equals
3682// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003683static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003684 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003685 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003686 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003687 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003688 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003689 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003690}
3691
3692
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003693MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
3694 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003695 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003696 // Handle [] indexing on Strings
3697 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003698 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3699 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003700 }
3701
3702 // Handle [] indexing on String objects
3703 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003704 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3705 Handle<Object> result =
3706 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3707 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003708 }
3709
3710 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003711 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003712 return prototype->GetElement(index);
3713 }
3714
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003715 return GetElement(object, index);
3716}
3717
3718
lrn@chromium.org303ada72010-10-27 09:33:13 +00003719MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003720 return object->GetElement(index);
3721}
3722
3723
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003724MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
3725 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003726 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003727 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003728
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003729 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003730 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003731 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003732 isolate->factory()->NewTypeError("non_object_property_load",
3733 HandleVector(args, 2));
3734 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003735 }
3736
3737 // Check if the given key is an array index.
3738 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003739 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003740 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003741 }
3742
3743 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003744 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003745 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003746 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003747 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003748 bool has_pending_exception = false;
3749 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003750 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003751 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003752 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003753 }
3754
ager@chromium.org32912102009-01-16 10:38:43 +00003755 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003756 // the element if so.
3757 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003758 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003759 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003760 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003761 }
3762}
3763
3764
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003765RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003766 NoHandleAllocation ha;
3767 ASSERT(args.length() == 2);
3768
3769 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003770 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003771
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003772 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003773}
3774
3775
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003776// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003777RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003778 NoHandleAllocation ha;
3779 ASSERT(args.length() == 2);
3780
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003781 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003782 // itself.
3783 //
3784 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003785 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003786 // global proxy object never has properties. This is the case
3787 // because the global proxy object forwards everything to its hidden
3788 // prototype including local lookups.
3789 //
3790 // Additionally, we need to make sure that we do not cache results
3791 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003792 if (args[0]->IsJSObject() &&
3793 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003794 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003795 args[1]->IsString()) {
3796 JSObject* receiver = JSObject::cast(args[0]);
3797 String* key = String::cast(args[1]);
3798 if (receiver->HasFastProperties()) {
3799 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003800 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003801 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
3802 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003803 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003804 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003805 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003806 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003807 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003808 LookupResult result;
3809 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003810 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003811 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003812 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003813 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003814 }
3815 } else {
3816 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003817 StringDictionary* dictionary = receiver->property_dictionary();
3818 int entry = dictionary->FindEntry(key);
3819 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003820 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003821 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003822 if (!receiver->IsGlobalObject()) return value;
3823 value = JSGlobalPropertyCell::cast(value)->value();
3824 if (!value->IsTheHole()) return value;
3825 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003826 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003827 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003828 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3829 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003830 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003831 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003832 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003833 if (index >= 0 && index < str->length()) {
3834 Handle<Object> result = GetCharAt(str, index);
3835 return *result;
3836 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003837 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003838
3839 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003840 return Runtime::GetObjectProperty(isolate,
3841 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00003842 args.at<Object>(1));
3843}
3844
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003845// Implements part of 8.12.9 DefineOwnProperty.
3846// There are 3 cases that lead here:
3847// Step 4b - define a new accessor property.
3848// Steps 9c & 12 - replace an existing data property with an accessor property.
3849// Step 12 - update an existing accessor property with an accessor or generic
3850// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003851RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003852 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003853 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003854 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3855 CONVERT_CHECKED(String, name, args[1]);
3856 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003857 Object* fun = args[3];
3858 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00003859 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3860 int unchecked = flag_attr->value();
3861 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3862 RUNTIME_ASSERT(!obj->IsNull());
3863 LookupResult result;
3864 obj->LocalLookupRealNamedProperty(name, &result);
3865
3866 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3867 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3868 // delete it to avoid running into trouble in DefineAccessor, which
3869 // handles this incorrectly if the property is readonly (does nothing)
3870 if (result.IsProperty() &&
3871 (result.type() == FIELD || result.type() == NORMAL
3872 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003873 Object* ok;
3874 { MaybeObject* maybe_ok =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003875 obj->DeleteProperty(name, JSReceiver::NORMAL_DELETION);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003876 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3877 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003878 }
3879 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3880}
3881
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003882// Implements part of 8.12.9 DefineOwnProperty.
3883// There are 3 cases that lead here:
3884// Step 4a - define a new data property.
3885// Steps 9b & 12 - replace an existing accessor property with a data property.
3886// Step 12 - update an existing data property with a data or generic
3887// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003888RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003889 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003890 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003891 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3892 CONVERT_ARG_CHECKED(String, name, 1);
3893 Handle<Object> obj_value = args.at<Object>(2);
3894
3895 CONVERT_CHECKED(Smi, flag, args[3]);
3896 int unchecked = flag->value();
3897 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3898
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003899 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3900
3901 // Check if this is an element.
3902 uint32_t index;
3903 bool is_element = name->AsArrayIndex(&index);
3904
3905 // Special case for elements if any of the flags are true.
3906 // If elements are in fast case we always implicitly assume that:
3907 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3908 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3909 is_element) {
3910 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003911 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003912 // We do not need to do access checks here since these has already
3913 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003914 Handle<Object> proto(js_object->GetPrototype());
3915 // If proxy is detached, ignore the assignment. Alternatively,
3916 // we could throw an exception.
3917 if (proto->IsNull()) return *obj_value;
3918 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003919 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003920 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003921 // Make sure that we never go back to fast case.
3922 dictionary->set_requires_slow_elements();
3923 PropertyDetails details = PropertyDetails(attr, NORMAL);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003924 Handle<NumberDictionary> extended_dictionary =
3925 NumberDictionarySet(dictionary, index, obj_value, details);
3926 if (*extended_dictionary != *dictionary) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003927 if (js_object->GetElementsKind() ==
3928 JSObject::NON_STRICT_ARGUMENTS_ELEMENTS) {
3929 FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
3930 } else {
3931 js_object->set_elements(*extended_dictionary);
3932 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003933 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003934 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003935 }
3936
ager@chromium.org5c838252010-02-19 08:53:10 +00003937 LookupResult result;
whesse@chromium.org7b260152011-06-20 15:33:18 +00003938 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003939
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003940 // To be compatible with safari we do not change the value on API objects
3941 // in defineProperty. Firefox disagrees here, and actually changes the value.
3942 if (result.IsProperty() &&
3943 (result.type() == CALLBACKS) &&
3944 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003945 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003946 }
3947
ager@chromium.org5c838252010-02-19 08:53:10 +00003948 // Take special care when attributes are different and there is already
3949 // a property. For simplicity we normalize the property which enables us
3950 // to not worry about changing the instance_descriptor and creating a new
3951 // map. The current version of SetObjectProperty does not handle attributes
3952 // correctly in the case where a property is a field and is reset with
3953 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003954 if (result.IsProperty() &&
3955 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003956 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003957 if (js_object->IsJSGlobalProxy()) {
3958 // Since the result is a property, the prototype will exist so
3959 // we don't have to check for null.
3960 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003961 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003962 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003963 // Use IgnoreAttributes version since a readonly property may be
3964 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003965 return js_object->SetLocalPropertyIgnoreAttributes(*name,
3966 *obj_value,
3967 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003968 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003969
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003970 return Runtime::ForceSetObjectProperty(isolate,
3971 js_object,
3972 name,
3973 obj_value,
3974 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003975}
3976
3977
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003978// Special case for elements if any of the flags are true.
3979// If elements are in fast case we always implicitly assume that:
3980// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3981static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
3982 Handle<JSObject> js_object,
3983 uint32_t index,
3984 Handle<Object> value,
3985 PropertyAttributes attr) {
3986 // Normalize the elements to enable attributes on the property.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003987 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003988 // Make sure that we never go back to fast case.
3989 dictionary->set_requires_slow_elements();
3990 PropertyDetails details = PropertyDetails(attr, NORMAL);
3991 Handle<NumberDictionary> extended_dictionary =
3992 NumberDictionarySet(dictionary, index, value, details);
3993 if (*extended_dictionary != *dictionary) {
3994 js_object->set_elements(*extended_dictionary);
3995 }
3996 return *value;
3997}
3998
3999
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004000MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4001 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004002 Handle<Object> key,
4003 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004004 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004005 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004006 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004007
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004008 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004009 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004010 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004011 isolate->factory()->NewTypeError("non_object_property_store",
4012 HandleVector(args, 2));
4013 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004014 }
4015
4016 // If the object isn't a JavaScript object, we ignore the store.
4017 if (!object->IsJSObject()) return *value;
4018
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004019 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4020
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004021 // Check if the given key is an array index.
4022 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004023 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004024 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4025 // of a string using [] notation. We need to support this too in
4026 // JavaScript.
4027 // In the case of a String object we just need to redirect the assignment to
4028 // the underlying string if the index is in range. Since the underlying
4029 // string does nothing with the assignment then we can ignore such
4030 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004031 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004032 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004033 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004034
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004035 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4036 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
4037 }
4038
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004039 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004040 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004041 return *value;
4042 }
4043
4044 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004045 Handle<Object> result;
4046 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004047 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4048 return NormalizeObjectSetElement(isolate,
4049 js_object,
4050 index,
4051 value,
4052 attr);
4053 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004054 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004055 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004056 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004057 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004058 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004059 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004060 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004061 return *value;
4062 }
4063
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004064 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004065 bool has_pending_exception = false;
4066 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4067 if (has_pending_exception) return Failure::Exception();
4068 Handle<String> name = Handle<String>::cast(converted);
4069
4070 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004071 return js_object->SetElement(index, *value, strict_mode, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004072 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004073 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004074 }
4075}
4076
4077
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004078MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4079 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004080 Handle<Object> key,
4081 Handle<Object> value,
4082 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004083 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004084
4085 // Check if the given key is an array index.
4086 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004087 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004088 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4089 // of a string using [] notation. We need to support this too in
4090 // JavaScript.
4091 // In the case of a String object we just need to redirect the assignment to
4092 // the underlying string if the index is in range. Since the underlying
4093 // string does nothing with the assignment then we can ignore such
4094 // assignments.
4095 if (js_object->IsStringObjectWithCharacterAt(index)) {
4096 return *value;
4097 }
4098
whesse@chromium.org7b260152011-06-20 15:33:18 +00004099 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004100 }
4101
4102 if (key->IsString()) {
4103 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004104 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004105 } else {
4106 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004107 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004108 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4109 *value,
4110 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004111 }
4112 }
4113
4114 // Call-back into JavaScript to convert the key to a string.
4115 bool has_pending_exception = false;
4116 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4117 if (has_pending_exception) return Failure::Exception();
4118 Handle<String> name = Handle<String>::cast(converted);
4119
4120 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004121 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004122 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004123 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004124 }
4125}
4126
4127
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004128MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004129 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004130 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004131 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004132
4133 // Check if the given key is an array index.
4134 uint32_t index;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004135 if (receiver->IsJSObject() && key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004136 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4137 // characters of a string using [] notation. In the case of a
4138 // String object we just need to redirect the deletion to the
4139 // underlying string if the index is in range. Since the
4140 // underlying string does nothing with the deletion, we can ignore
4141 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004142 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004143 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004144 }
4145
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004146 return JSObject::cast(*receiver)->DeleteElement(
4147 index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004148 }
4149
4150 Handle<String> key_string;
4151 if (key->IsString()) {
4152 key_string = Handle<String>::cast(key);
4153 } else {
4154 // Call-back into JavaScript to convert the key to a string.
4155 bool has_pending_exception = false;
4156 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4157 if (has_pending_exception) return Failure::Exception();
4158 key_string = Handle<String>::cast(converted);
4159 }
4160
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004161 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004162 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004163}
4164
4165
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004166RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004167 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004168 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004169
4170 Handle<Object> object = args.at<Object>(0);
4171 Handle<Object> key = args.at<Object>(1);
4172 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004173 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004174 RUNTIME_ASSERT(
4175 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004176 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004177 PropertyAttributes attributes =
4178 static_cast<PropertyAttributes>(unchecked_attributes);
4179
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004180 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004181 if (args.length() == 5) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004182 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004183 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4184 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004185 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004186 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004187
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004188 return Runtime::SetObjectProperty(isolate,
4189 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004190 key,
4191 value,
4192 attributes,
4193 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004194}
4195
4196
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004197// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004198// This is used to decide if we should transform null and undefined
4199// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004200RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004201 NoHandleAllocation ha;
4202 RUNTIME_ASSERT(args.length() == 1);
4203
4204 Handle<Object> object = args.at<Object>(0);
4205
4206 if (object->IsJSFunction()) {
4207 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004208 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004209 }
4210 return isolate->heap()->undefined_value();
4211}
4212
4213
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004214// Set a local property, even if it is READ_ONLY. If the property does not
4215// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004216RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004217 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004218 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004219 CONVERT_CHECKED(JSObject, object, args[0]);
4220 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004221 // Compute attributes.
4222 PropertyAttributes attributes = NONE;
4223 if (args.length() == 4) {
4224 CONVERT_CHECKED(Smi, value_obj, args[3]);
4225 int unchecked_value = value_obj->value();
4226 // Only attribute bits should be set.
4227 RUNTIME_ASSERT(
4228 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4229 attributes = static_cast<PropertyAttributes>(unchecked_value);
4230 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004231
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004232 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004233 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004234}
4235
4236
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004237RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004238 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004239 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004240
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004241 CONVERT_CHECKED(JSReceiver, object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004242 CONVERT_CHECKED(String, key, args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004243 CONVERT_SMI_ARG_CHECKED(strict, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004244 return object->DeleteProperty(key, (strict == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004245 ? JSReceiver::STRICT_DELETION
4246 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004247}
4248
4249
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004250static Object* HasLocalPropertyImplementation(Isolate* isolate,
4251 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004252 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004253 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004254 // Handle hidden prototypes. If there's a hidden prototype above this thing
4255 // then we have to check it for properties, because they are supposed to
4256 // look like they are on this object.
4257 Handle<Object> proto(object->GetPrototype());
4258 if (proto->IsJSObject() &&
4259 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004260 return HasLocalPropertyImplementation(isolate,
4261 Handle<JSObject>::cast(proto),
4262 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004263 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004264 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004265}
4266
4267
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004268RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004269 NoHandleAllocation ha;
4270 ASSERT(args.length() == 2);
4271 CONVERT_CHECKED(String, key, args[1]);
4272
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004273 uint32_t index;
4274 const bool key_is_array_index = key->AsArrayIndex(&index);
4275
ager@chromium.org9085a012009-05-11 19:22:57 +00004276 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004277 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004278 if (obj->IsJSObject()) {
4279 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004280 // Fast case: either the key is a real named property or it is not
4281 // an array index and there are no interceptors or hidden
4282 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004283 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004284 Map* map = object->map();
4285 if (!key_is_array_index &&
4286 !map->has_named_interceptor() &&
4287 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4288 return isolate->heap()->false_value();
4289 }
4290 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004291 HandleScope scope(isolate);
4292 return HasLocalPropertyImplementation(isolate,
4293 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004294 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004295 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004296 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004297 String* string = String::cast(obj);
4298 if (index < static_cast<uint32_t>(string->length())) {
4299 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004300 }
4301 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004302 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004303}
4304
4305
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004306RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004307 NoHandleAllocation na;
4308 ASSERT(args.length() == 2);
4309
4310 // Only JS objects can have properties.
4311 if (args[0]->IsJSObject()) {
4312 JSObject* object = JSObject::cast(args[0]);
4313 CONVERT_CHECKED(String, key, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004314 if (object->HasProperty(key)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004315 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004316 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004317}
4318
4319
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004320RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004321 NoHandleAllocation na;
4322 ASSERT(args.length() == 2);
4323
4324 // Only JS objects can have elements.
4325 if (args[0]->IsJSObject()) {
4326 JSObject* object = JSObject::cast(args[0]);
4327 CONVERT_CHECKED(Smi, index_obj, args[1]);
4328 uint32_t index = index_obj->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004329 if (object->HasElement(index)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004330 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004331 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004332}
4333
4334
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004335RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004336 NoHandleAllocation ha;
4337 ASSERT(args.length() == 2);
4338
4339 CONVERT_CHECKED(JSObject, object, args[0]);
4340 CONVERT_CHECKED(String, key, args[1]);
4341
4342 uint32_t index;
4343 if (key->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004344 return isolate->heap()->ToBoolean(object->HasElement(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004345 }
4346
ager@chromium.org870a0b62008-11-04 11:43:05 +00004347 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004348 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004349}
4350
4351
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004352RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004353 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004354 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004355 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004356 return *GetKeysFor(object);
4357}
4358
4359
4360// Returns either a FixedArray as Runtime_GetPropertyNames,
4361// or, if the given object has an enum cache that contains
4362// all enumerable properties of the object and its prototypes
4363// have none, the map of the object. This is used to speed up
4364// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004365RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004366 ASSERT(args.length() == 1);
4367
4368 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4369
4370 if (raw_object->IsSimpleEnum()) return raw_object->map();
4371
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004372 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004373 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004374 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4375 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004376
4377 // Test again, since cache may have been built by preceding call.
4378 if (object->IsSimpleEnum()) return object->map();
4379
4380 return *content;
4381}
4382
4383
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004384// Find the length of the prototype chain that is to to handled as one. If a
4385// prototype object is hidden it is to be viewed as part of the the object it
4386// is prototype for.
4387static int LocalPrototypeChainLength(JSObject* obj) {
4388 int count = 1;
4389 Object* proto = obj->GetPrototype();
4390 while (proto->IsJSObject() &&
4391 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4392 count++;
4393 proto = JSObject::cast(proto)->GetPrototype();
4394 }
4395 return count;
4396}
4397
4398
4399// Return the names of the local named properties.
4400// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004401RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004402 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004403 ASSERT(args.length() == 1);
4404 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004405 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004406 }
4407 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4408
4409 // Skip the global proxy as it has no properties and always delegates to the
4410 // real global object.
4411 if (obj->IsJSGlobalProxy()) {
4412 // Only collect names if access is permitted.
4413 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004414 !isolate->MayNamedAccess(*obj,
4415 isolate->heap()->undefined_value(),
4416 v8::ACCESS_KEYS)) {
4417 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4418 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004419 }
4420 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4421 }
4422
4423 // Find the number of objects making up this.
4424 int length = LocalPrototypeChainLength(*obj);
4425
4426 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004427 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004428 int total_property_count = 0;
4429 Handle<JSObject> jsproto = obj;
4430 for (int i = 0; i < length; i++) {
4431 // Only collect names if access is permitted.
4432 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004433 !isolate->MayNamedAccess(*jsproto,
4434 isolate->heap()->undefined_value(),
4435 v8::ACCESS_KEYS)) {
4436 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4437 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004438 }
4439 int n;
4440 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4441 local_property_count[i] = n;
4442 total_property_count += n;
4443 if (i < length - 1) {
4444 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4445 }
4446 }
4447
4448 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004449 Handle<FixedArray> names =
4450 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004451
4452 // Get the property names.
4453 jsproto = obj;
4454 int proto_with_hidden_properties = 0;
4455 for (int i = 0; i < length; i++) {
4456 jsproto->GetLocalPropertyNames(*names,
4457 i == 0 ? 0 : local_property_count[i - 1]);
4458 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
4459 proto_with_hidden_properties++;
4460 }
4461 if (i < length - 1) {
4462 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4463 }
4464 }
4465
4466 // Filter out name of hidden propeties object.
4467 if (proto_with_hidden_properties > 0) {
4468 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004469 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004470 names->length() - proto_with_hidden_properties);
4471 int dest_pos = 0;
4472 for (int i = 0; i < total_property_count; i++) {
4473 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004474 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004475 continue;
4476 }
4477 names->set(dest_pos++, name);
4478 }
4479 }
4480
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004481 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004482}
4483
4484
4485// Return the names of the local indexed properties.
4486// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004487RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004488 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004489 ASSERT(args.length() == 1);
4490 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004491 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004492 }
4493 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4494
4495 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004496 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004497 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004498 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004499}
4500
4501
4502// Return information on whether an object has a named or indexed interceptor.
4503// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004504RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004505 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004506 ASSERT(args.length() == 1);
4507 if (!args[0]->IsJSObject()) {
4508 return Smi::FromInt(0);
4509 }
4510 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4511
4512 int result = 0;
4513 if (obj->HasNamedInterceptor()) result |= 2;
4514 if (obj->HasIndexedInterceptor()) result |= 1;
4515
4516 return Smi::FromInt(result);
4517}
4518
4519
4520// Return property names from named interceptor.
4521// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004522RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004523 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004524 ASSERT(args.length() == 1);
4525 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4526
4527 if (obj->HasNamedInterceptor()) {
4528 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4529 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4530 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004531 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004532}
4533
4534
4535// Return element names from indexed interceptor.
4536// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004537RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004538 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004539 ASSERT(args.length() == 1);
4540 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4541
4542 if (obj->HasIndexedInterceptor()) {
4543 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4544 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4545 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004546 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004547}
4548
4549
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004550RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004551 ASSERT_EQ(args.length(), 1);
4552 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004553 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004554 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004555
4556 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004557 // Do access checks before going to the global object.
4558 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004559 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004560 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004561 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4562 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004563 }
4564
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004565 Handle<Object> proto(object->GetPrototype());
4566 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004567 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004568 object = Handle<JSObject>::cast(proto);
4569 }
4570
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004571 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4572 LOCAL_ONLY);
4573 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4574 // property array and since the result is mutable we have to create
4575 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004576 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004577 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004578 for (int i = 0; i < length; i++) {
4579 Object* entry = contents->get(i);
4580 if (entry->IsString()) {
4581 copy->set(i, entry);
4582 } else {
4583 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004584 HandleScope scope(isolate);
4585 Handle<Object> entry_handle(entry, isolate);
4586 Handle<Object> entry_str =
4587 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004588 copy->set(i, *entry_str);
4589 }
4590 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004591 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004592}
4593
4594
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004595RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004596 NoHandleAllocation ha;
4597 ASSERT(args.length() == 1);
4598
4599 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004600 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004601 it.AdvanceToArgumentsFrame();
4602 JavaScriptFrame* frame = it.frame();
4603
4604 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004605 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004606
4607 // Try to convert the key to an index. If successful and within
4608 // index return the the argument from the frame.
4609 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004610 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004611 return frame->GetParameter(index);
4612 }
4613
4614 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004615 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004616 bool exception = false;
4617 Handle<Object> converted =
4618 Execution::ToString(args.at<Object>(0), &exception);
4619 if (exception) return Failure::Exception();
4620 Handle<String> key = Handle<String>::cast(converted);
4621
4622 // Try to convert the string key into an array index.
4623 if (key->AsArrayIndex(&index)) {
4624 if (index < n) {
4625 return frame->GetParameter(index);
4626 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004627 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004628 }
4629 }
4630
4631 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004632 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
4633 if (key->Equals(isolate->heap()->callee_symbol())) {
4634 Object* function = frame->function();
4635 if (function->IsJSFunction() &&
4636 JSFunction::cast(function)->shared()->strict_mode()) {
4637 return isolate->Throw(*isolate->factory()->NewTypeError(
4638 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
4639 }
4640 return function;
4641 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004642
4643 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004644 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004645}
4646
4647
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004648RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004649 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004650
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004651 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004652 Handle<Object> object = args.at<Object>(0);
4653 if (object->IsJSObject()) {
4654 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004655 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004656 MaybeObject* ok = js_object->TransformToFastProperties(0);
4657 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004658 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004659 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004660 return *object;
4661}
4662
4663
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004664RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004665 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004666
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004667 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004668 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004669 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004670 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004671 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004672 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004673 return *object;
4674}
4675
4676
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004677RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004678 NoHandleAllocation ha;
4679 ASSERT(args.length() == 1);
4680
4681 return args[0]->ToBoolean();
4682}
4683
4684
4685// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4686// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004687RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004688 NoHandleAllocation ha;
4689
4690 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004691 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004692 HeapObject* heap_obj = HeapObject::cast(obj);
4693
4694 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004695 if (heap_obj->map()->is_undetectable()) {
4696 return isolate->heap()->undefined_symbol();
4697 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004698
4699 InstanceType instance_type = heap_obj->map()->instance_type();
4700 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004701 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004702 }
4703
4704 switch (instance_type) {
4705 case ODDBALL_TYPE:
4706 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004707 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004708 }
4709 if (heap_obj->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004710 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004711 }
4712 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004713 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004714 case JS_FUNCTION_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004715 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004716 default:
4717 // For any kind of object not handled above, the spec rule for
4718 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004719 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004720 }
4721}
4722
4723
lrn@chromium.org25156de2010-04-06 13:10:27 +00004724static bool AreDigits(const char*s, int from, int to) {
4725 for (int i = from; i < to; i++) {
4726 if (s[i] < '0' || s[i] > '9') return false;
4727 }
4728
4729 return true;
4730}
4731
4732
4733static int ParseDecimalInteger(const char*s, int from, int to) {
4734 ASSERT(to - from < 10); // Overflow is not possible.
4735 ASSERT(from < to);
4736 int d = s[from] - '0';
4737
4738 for (int i = from + 1; i < to; i++) {
4739 d = 10 * d + (s[i] - '0');
4740 }
4741
4742 return d;
4743}
4744
4745
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004746RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004747 NoHandleAllocation ha;
4748 ASSERT(args.length() == 1);
4749 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004750 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004751
4752 // Fast case: short integer or some sorts of junk values.
4753 int len = subject->length();
4754 if (subject->IsSeqAsciiString()) {
4755 if (len == 0) return Smi::FromInt(0);
4756
4757 char const* data = SeqAsciiString::cast(subject)->GetChars();
4758 bool minus = (data[0] == '-');
4759 int start_pos = (minus ? 1 : 0);
4760
4761 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004762 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004763 } else if (data[start_pos] > '9') {
4764 // Fast check for a junk value. A valid string may start from a
4765 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4766 // the 'I' character ('Infinity'). All of that have codes not greater than
4767 // '9' except 'I'.
4768 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004769 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004770 }
4771 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4772 // The maximal/minimal smi has 10 digits. If the string has less digits we
4773 // know it will fit into the smi-data type.
4774 int d = ParseDecimalInteger(data, start_pos, len);
4775 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004776 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004777 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004778 } else if (!subject->HasHashCode() &&
4779 len <= String::kMaxArrayIndexSize &&
4780 (len == 1 || data[0] != '0')) {
4781 // String hash is not calculated yet but all the data are present.
4782 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004783 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004784#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004785 subject->Hash(); // Force hash calculation.
4786 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4787 static_cast<int>(hash));
4788#endif
4789 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004790 }
4791 return Smi::FromInt(d);
4792 }
4793 }
4794
4795 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004796 return isolate->heap()->NumberFromDouble(
4797 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004798}
4799
4800
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004801RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004802 NoHandleAllocation ha;
4803 ASSERT(args.length() == 1);
4804
4805 CONVERT_CHECKED(JSArray, codes, args[0]);
4806 int length = Smi::cast(codes->length())->value();
4807
4808 // Check if the string can be ASCII.
4809 int i;
4810 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004811 Object* element;
4812 { MaybeObject* maybe_element = codes->GetElement(i);
4813 // We probably can't get an exception here, but just in order to enforce
4814 // the checking of inputs in the runtime calls we check here.
4815 if (!maybe_element->ToObject(&element)) return maybe_element;
4816 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004817 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4818 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4819 break;
4820 }
4821
lrn@chromium.org303ada72010-10-27 09:33:13 +00004822 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004823 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004824 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004825 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004826 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004827 }
4828
lrn@chromium.org303ada72010-10-27 09:33:13 +00004829 Object* object = NULL;
4830 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004831 String* result = String::cast(object);
4832 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004833 Object* element;
4834 { MaybeObject* maybe_element = codes->GetElement(i);
4835 if (!maybe_element->ToObject(&element)) return maybe_element;
4836 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004837 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004838 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004839 }
4840 return result;
4841}
4842
4843
4844// kNotEscaped is generated by the following:
4845//
4846// #!/bin/perl
4847// for (my $i = 0; $i < 256; $i++) {
4848// print "\n" if $i % 16 == 0;
4849// my $c = chr($i);
4850// my $escaped = 1;
4851// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4852// print $escaped ? "0, " : "1, ";
4853// }
4854
4855
4856static bool IsNotEscaped(uint16_t character) {
4857 // Only for 8 bit characters, the rest are always escaped (in a different way)
4858 ASSERT(character < 256);
4859 static const char kNotEscaped[256] = {
4860 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4861 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4862 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4863 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4864 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4865 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4866 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4867 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
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, 0, 0, 0, 0, 0, 0,
4871 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4872 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4873 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4874 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4875 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4876 };
4877 return kNotEscaped[character] != 0;
4878}
4879
4880
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004881RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004882 const char hex_chars[] = "0123456789ABCDEF";
4883 NoHandleAllocation ha;
4884 ASSERT(args.length() == 1);
4885 CONVERT_CHECKED(String, source, args[0]);
4886
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004887 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004888
4889 int escaped_length = 0;
4890 int length = source->length();
4891 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004892 Access<StringInputBuffer> buffer(
4893 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004894 buffer->Reset(source);
4895 while (buffer->has_more()) {
4896 uint16_t character = buffer->GetNext();
4897 if (character >= 256) {
4898 escaped_length += 6;
4899 } else if (IsNotEscaped(character)) {
4900 escaped_length++;
4901 } else {
4902 escaped_length += 3;
4903 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004904 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004905 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004906 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004907 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004908 return Failure::OutOfMemoryException();
4909 }
4910 }
4911 }
4912 // No length change implies no change. Return original string if no change.
4913 if (escaped_length == length) {
4914 return source;
4915 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004916 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004917 { MaybeObject* maybe_o =
4918 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004919 if (!maybe_o->ToObject(&o)) return maybe_o;
4920 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004921 String* destination = String::cast(o);
4922 int dest_position = 0;
4923
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004924 Access<StringInputBuffer> buffer(
4925 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004926 buffer->Rewind();
4927 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004928 uint16_t chr = buffer->GetNext();
4929 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004930 destination->Set(dest_position, '%');
4931 destination->Set(dest_position+1, 'u');
4932 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4933 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4934 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4935 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004936 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004937 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004938 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004939 dest_position++;
4940 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004941 destination->Set(dest_position, '%');
4942 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4943 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004944 dest_position += 3;
4945 }
4946 }
4947 return destination;
4948}
4949
4950
4951static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4952 static const signed char kHexValue['g'] = {
4953 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4954 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4955 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4956 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4957 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4958 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4959 -1, 10, 11, 12, 13, 14, 15 };
4960
4961 if (character1 > 'f') return -1;
4962 int hi = kHexValue[character1];
4963 if (hi == -1) return -1;
4964 if (character2 > 'f') return -1;
4965 int lo = kHexValue[character2];
4966 if (lo == -1) return -1;
4967 return (hi << 4) + lo;
4968}
4969
4970
ager@chromium.org870a0b62008-11-04 11:43:05 +00004971static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004972 int i,
4973 int length,
4974 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004975 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004976 int32_t hi = 0;
4977 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004978 if (character == '%' &&
4979 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004980 source->Get(i + 1) == 'u' &&
4981 (hi = TwoDigitHex(source->Get(i + 2),
4982 source->Get(i + 3))) != -1 &&
4983 (lo = TwoDigitHex(source->Get(i + 4),
4984 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004985 *step = 6;
4986 return (hi << 8) + lo;
4987 } else if (character == '%' &&
4988 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004989 (lo = TwoDigitHex(source->Get(i + 1),
4990 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004991 *step = 3;
4992 return lo;
4993 } else {
4994 *step = 1;
4995 return character;
4996 }
4997}
4998
4999
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005000RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005001 NoHandleAllocation ha;
5002 ASSERT(args.length() == 1);
5003 CONVERT_CHECKED(String, source, args[0]);
5004
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005005 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005006
5007 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005008 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005009
5010 int unescaped_length = 0;
5011 for (int i = 0; i < length; unescaped_length++) {
5012 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005013 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005014 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005015 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005016 i += step;
5017 }
5018
5019 // No length change implies no change. Return original string if no change.
5020 if (unescaped_length == length)
5021 return source;
5022
lrn@chromium.org303ada72010-10-27 09:33:13 +00005023 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005024 { MaybeObject* maybe_o =
5025 ascii ?
5026 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5027 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005028 if (!maybe_o->ToObject(&o)) return maybe_o;
5029 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005030 String* destination = String::cast(o);
5031
5032 int dest_position = 0;
5033 for (int i = 0; i < length; dest_position++) {
5034 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005035 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005036 i += step;
5037 }
5038 return destination;
5039}
5040
5041
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005042static const unsigned int kQuoteTableLength = 128u;
5043
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005044static const int kJsonQuotesCharactersPerEntry = 8;
5045static const char* const JsonQuotes =
5046 "\\u0000 \\u0001 \\u0002 \\u0003 "
5047 "\\u0004 \\u0005 \\u0006 \\u0007 "
5048 "\\b \\t \\n \\u000b "
5049 "\\f \\r \\u000e \\u000f "
5050 "\\u0010 \\u0011 \\u0012 \\u0013 "
5051 "\\u0014 \\u0015 \\u0016 \\u0017 "
5052 "\\u0018 \\u0019 \\u001a \\u001b "
5053 "\\u001c \\u001d \\u001e \\u001f "
5054 " ! \\\" # "
5055 "$ % & ' "
5056 "( ) * + "
5057 ", - . / "
5058 "0 1 2 3 "
5059 "4 5 6 7 "
5060 "8 9 : ; "
5061 "< = > ? "
5062 "@ A B C "
5063 "D E F G "
5064 "H I J K "
5065 "L M N O "
5066 "P Q R S "
5067 "T U V W "
5068 "X Y Z [ "
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 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005078
5079
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005080// For a string that is less than 32k characters it should always be
5081// possible to allocate it in new space.
5082static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5083
5084
5085// Doing JSON quoting cannot make the string more than this many times larger.
5086static const int kJsonQuoteWorstCaseBlowup = 6;
5087
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005088static const int kSpaceForQuotesAndComma = 3;
5089static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005090
5091// Covers the entire ASCII range (all other characters are unchanged by JSON
5092// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005093static const byte JsonQuoteLengths[kQuoteTableLength] = {
5094 6, 6, 6, 6, 6, 6, 6, 6,
5095 2, 2, 2, 6, 2, 2, 6, 6,
5096 6, 6, 6, 6, 6, 6, 6, 6,
5097 6, 6, 6, 6, 6, 6, 6, 6,
5098 1, 1, 2, 1, 1, 1, 1, 1,
5099 1, 1, 1, 1, 1, 1, 1, 1,
5100 1, 1, 1, 1, 1, 1, 1, 1,
5101 1, 1, 1, 1, 1, 1, 1, 1,
5102 1, 1, 1, 1, 1, 1, 1, 1,
5103 1, 1, 1, 1, 1, 1, 1, 1,
5104 1, 1, 1, 1, 1, 1, 1, 1,
5105 1, 1, 1, 1, 2, 1, 1, 1,
5106 1, 1, 1, 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};
5111
5112
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005113template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005114MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005115
5116
5117template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005118MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5119 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005120}
5121
5122
5123template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005124MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5125 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005126}
5127
5128
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005129template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005130static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5131 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005132 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005133 const Char* read_cursor = characters.start();
5134 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005135 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005136 int quoted_length = kSpaceForQuotes;
5137 while (read_cursor < end) {
5138 Char c = *(read_cursor++);
5139 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5140 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005141 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005142 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005143 }
5144 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005145 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5146 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005147 Object* new_object;
5148 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005149 return new_alloc;
5150 }
5151 StringType* new_string = StringType::cast(new_object);
5152
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005153 Char* write_cursor = reinterpret_cast<Char*>(
5154 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005155 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005156 *(write_cursor++) = '"';
5157
5158 read_cursor = characters.start();
5159 while (read_cursor < end) {
5160 Char c = *(read_cursor++);
5161 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5162 *(write_cursor++) = c;
5163 } else {
5164 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5165 const char* replacement = JsonQuotes +
5166 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5167 for (int i = 0; i < len; i++) {
5168 *write_cursor++ = *replacement++;
5169 }
5170 }
5171 }
5172 *(write_cursor++) = '"';
5173 return new_string;
5174}
5175
5176
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005177template <typename SinkChar, typename SourceChar>
5178static inline SinkChar* WriteQuoteJsonString(
5179 Isolate* isolate,
5180 SinkChar* write_cursor,
5181 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005182 // SinkChar is only char if SourceChar is guaranteed to be char.
5183 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005184 const SourceChar* read_cursor = characters.start();
5185 const SourceChar* end = read_cursor + characters.length();
5186 *(write_cursor++) = '"';
5187 while (read_cursor < end) {
5188 SourceChar c = *(read_cursor++);
5189 if (sizeof(SourceChar) > 1u &&
5190 static_cast<unsigned>(c) >= kQuoteTableLength) {
5191 *(write_cursor++) = static_cast<SinkChar>(c);
5192 } else {
5193 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5194 const char* replacement = JsonQuotes +
5195 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5196 write_cursor[0] = replacement[0];
5197 if (len > 1) {
5198 write_cursor[1] = replacement[1];
5199 if (len > 2) {
5200 ASSERT(len == 6);
5201 write_cursor[2] = replacement[2];
5202 write_cursor[3] = replacement[3];
5203 write_cursor[4] = replacement[4];
5204 write_cursor[5] = replacement[5];
5205 }
5206 }
5207 write_cursor += len;
5208 }
5209 }
5210 *(write_cursor++) = '"';
5211 return write_cursor;
5212}
5213
5214
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005215template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005216static MaybeObject* QuoteJsonString(Isolate* isolate,
5217 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005218 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005219 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005220 int worst_case_length =
5221 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005222 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005223 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005224 }
5225
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005226 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5227 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005228 Object* new_object;
5229 if (!new_alloc->ToObject(&new_object)) {
5230 return new_alloc;
5231 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005232 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005233 // Even if our string is small enough to fit in new space we still have to
5234 // handle it being allocated in old space as may happen in the third
5235 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5236 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005237 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005238 }
5239 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005240 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005241
5242 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5243 Char* write_cursor = reinterpret_cast<Char*>(
5244 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005245 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005246 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5247 write_cursor,
5248 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005249 int final_length = static_cast<int>(
5250 write_cursor - reinterpret_cast<Char*>(
5251 new_string->address() + SeqAsciiString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005252 isolate->heap()->new_space()->
5253 template ShrinkStringAtAllocationBoundary<StringType>(
5254 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005255 return new_string;
5256}
5257
5258
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005259RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005260 NoHandleAllocation ha;
5261 CONVERT_CHECKED(String, str, args[0]);
5262 if (!str->IsFlat()) {
5263 MaybeObject* try_flatten = str->TryFlatten();
5264 Object* flat;
5265 if (!try_flatten->ToObject(&flat)) {
5266 return try_flatten;
5267 }
5268 str = String::cast(flat);
5269 ASSERT(str->IsFlat());
5270 }
5271 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005272 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
5273 str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005274 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005275 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
5276 str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005277 }
5278}
5279
5280
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005281RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005282 NoHandleAllocation ha;
5283 CONVERT_CHECKED(String, str, args[0]);
5284 if (!str->IsFlat()) {
5285 MaybeObject* try_flatten = str->TryFlatten();
5286 Object* flat;
5287 if (!try_flatten->ToObject(&flat)) {
5288 return try_flatten;
5289 }
5290 str = String::cast(flat);
5291 ASSERT(str->IsFlat());
5292 }
5293 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005294 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
5295 str->ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005296 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005297 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
5298 str->ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005299 }
5300}
5301
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005302
5303template <typename Char, typename StringType>
5304static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5305 FixedArray* array,
5306 int worst_case_length) {
5307 int length = array->length();
5308
5309 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5310 worst_case_length);
5311 Object* new_object;
5312 if (!new_alloc->ToObject(&new_object)) {
5313 return new_alloc;
5314 }
5315 if (!isolate->heap()->new_space()->Contains(new_object)) {
5316 // Even if our string is small enough to fit in new space we still have to
5317 // handle it being allocated in old space as may happen in the third
5318 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5319 // CEntryStub::GenerateCore.
5320 return isolate->heap()->undefined_value();
5321 }
5322 AssertNoAllocation no_gc;
5323 StringType* new_string = StringType::cast(new_object);
5324 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5325
5326 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5327 Char* write_cursor = reinterpret_cast<Char*>(
5328 new_string->address() + SeqAsciiString::kHeaderSize);
5329 *(write_cursor++) = '[';
5330 for (int i = 0; i < length; i++) {
5331 if (i != 0) *(write_cursor++) = ',';
5332 String* str = String::cast(array->get(i));
5333 if (str->IsTwoByteRepresentation()) {
5334 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5335 write_cursor,
5336 str->ToUC16Vector());
5337 } else {
5338 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5339 write_cursor,
5340 str->ToAsciiVector());
5341 }
5342 }
5343 *(write_cursor++) = ']';
5344
5345 int final_length = static_cast<int>(
5346 write_cursor - reinterpret_cast<Char*>(
5347 new_string->address() + SeqAsciiString::kHeaderSize));
5348 isolate->heap()->new_space()->
5349 template ShrinkStringAtAllocationBoundary<StringType>(
5350 new_string, final_length);
5351 return new_string;
5352}
5353
5354
5355RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5356 NoHandleAllocation ha;
5357 ASSERT(args.length() == 1);
5358 CONVERT_CHECKED(JSArray, array, args[0]);
5359
5360 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5361 FixedArray* elements = FixedArray::cast(array->elements());
5362 int n = elements->length();
5363 bool ascii = true;
5364 int total_length = 0;
5365
5366 for (int i = 0; i < n; i++) {
5367 Object* elt = elements->get(i);
5368 if (!elt->IsString()) return isolate->heap()->undefined_value();
5369 String* element = String::cast(elt);
5370 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5371 total_length += element->length();
5372 if (ascii && element->IsTwoByteRepresentation()) {
5373 ascii = false;
5374 }
5375 }
5376
5377 int worst_case_length =
5378 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5379 + total_length * kJsonQuoteWorstCaseBlowup;
5380
5381 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5382 return isolate->heap()->undefined_value();
5383 }
5384
5385 if (ascii) {
5386 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5387 elements,
5388 worst_case_length);
5389 } else {
5390 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5391 elements,
5392 worst_case_length);
5393 }
5394}
5395
5396
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005397RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005398 NoHandleAllocation ha;
5399
5400 CONVERT_CHECKED(String, s, args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005401 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005402
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005403 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005404
lrn@chromium.org25156de2010-04-06 13:10:27 +00005405 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005406 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005407 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005408}
5409
5410
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005411RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005412 NoHandleAllocation ha;
5413 CONVERT_CHECKED(String, str, args[0]);
5414
5415 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005416 double value = StringToDouble(isolate->unicode_cache(),
5417 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005418
5419 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005420 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005421}
5422
5423
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005424template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005425MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005426 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005427 String* s,
5428 int length,
5429 int input_string_length,
5430 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005431 // We try this twice, once with the assumption that the result is no longer
5432 // than the input and, if that assumption breaks, again with the exact
5433 // length. This may not be pretty, but it is nicer than what was here before
5434 // and I hereby claim my vaffel-is.
5435 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005436 // Allocate the resulting string.
5437 //
5438 // NOTE: This assumes that the upper/lower case of an ascii
5439 // character is also ascii. This is currently the case, but it
5440 // might break in the future if we implement more context and locale
5441 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005442 Object* o;
5443 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005444 ? isolate->heap()->AllocateRawAsciiString(length)
5445 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005446 if (!maybe_o->ToObject(&o)) return maybe_o;
5447 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005448 String* result = String::cast(o);
5449 bool has_changed_character = false;
5450
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005451 // Convert all characters to upper case, assuming that they will fit
5452 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005453 Access<StringInputBuffer> buffer(
5454 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005455 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005456 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005457 // We can assume that the string is not empty
5458 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005459 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005460 bool has_next = buffer->has_more();
5461 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005462 int char_length = mapping->get(current, next, chars);
5463 if (char_length == 0) {
5464 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005465 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005466 i++;
5467 } else if (char_length == 1) {
5468 // Common case: converting the letter resulted in one character.
5469 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005470 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005471 has_changed_character = true;
5472 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005473 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005474 // We've assumed that the result would be as long as the
5475 // input but here is a character that converts to several
5476 // characters. No matter, we calculate the exact length
5477 // of the result and try the whole thing again.
5478 //
5479 // Note that this leaves room for optimization. We could just
5480 // memcpy what we already have to the result string. Also,
5481 // the result string is the last object allocated we could
5482 // "realloc" it and probably, in the vast majority of cases,
5483 // extend the existing string to be able to hold the full
5484 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005485 int next_length = 0;
5486 if (has_next) {
5487 next_length = mapping->get(next, 0, chars);
5488 if (next_length == 0) next_length = 1;
5489 }
5490 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005491 while (buffer->has_more()) {
5492 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005493 // NOTE: we use 0 as the next character here because, while
5494 // the next character may affect what a character converts to,
5495 // it does not in any case affect the length of what it convert
5496 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005497 int char_length = mapping->get(current, 0, chars);
5498 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005499 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005500 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005501 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005502 return Failure::OutOfMemoryException();
5503 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005504 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005505 // Try again with the real length.
5506 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005507 } else {
5508 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005509 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005510 i++;
5511 }
5512 has_changed_character = true;
5513 }
5514 current = next;
5515 }
5516 if (has_changed_character) {
5517 return result;
5518 } else {
5519 // If we didn't actually change anything in doing the conversion
5520 // we simple return the result and let the converted string
5521 // become garbage; there is no reason to keep two identical strings
5522 // alive.
5523 return s;
5524 }
5525}
5526
5527
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005528namespace {
5529
lrn@chromium.org303ada72010-10-27 09:33:13 +00005530static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5531
5532
5533// Given a word and two range boundaries returns a word with high bit
5534// set in every byte iff the corresponding input byte was strictly in
5535// the range (m, n). All the other bits in the result are cleared.
5536// This function is only useful when it can be inlined and the
5537// boundaries are statically known.
5538// Requires: all bytes in the input word and the boundaries must be
5539// ascii (less than 0x7F).
5540static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5541 // Every byte in an ascii string is less than or equal to 0x7F.
5542 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5543 // Use strict inequalities since in edge cases the function could be
5544 // further simplified.
5545 ASSERT(0 < m && m < n && n < 0x7F);
5546 // Has high bit set in every w byte less than n.
5547 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5548 // Has high bit set in every w byte greater than m.
5549 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5550 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5551}
5552
5553
5554enum AsciiCaseConversion {
5555 ASCII_TO_LOWER,
5556 ASCII_TO_UPPER
5557};
5558
5559
5560template <AsciiCaseConversion dir>
5561struct FastAsciiConverter {
5562 static bool Convert(char* dst, char* src, int length) {
5563#ifdef DEBUG
5564 char* saved_dst = dst;
5565 char* saved_src = src;
5566#endif
5567 // We rely on the distance between upper and lower case letters
5568 // being a known power of 2.
5569 ASSERT('a' - 'A' == (1 << 5));
5570 // Boundaries for the range of input characters than require conversion.
5571 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5572 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5573 bool changed = false;
5574 char* const limit = src + length;
5575#ifdef V8_HOST_CAN_READ_UNALIGNED
5576 // Process the prefix of the input that requires no conversion one
5577 // (machine) word at a time.
5578 while (src <= limit - sizeof(uintptr_t)) {
5579 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5580 if (AsciiRangeMask(w, lo, hi) != 0) {
5581 changed = true;
5582 break;
5583 }
5584 *reinterpret_cast<uintptr_t*>(dst) = w;
5585 src += sizeof(uintptr_t);
5586 dst += sizeof(uintptr_t);
5587 }
5588 // Process the remainder of the input performing conversion when
5589 // required one word at a time.
5590 while (src <= limit - sizeof(uintptr_t)) {
5591 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5592 uintptr_t m = AsciiRangeMask(w, lo, hi);
5593 // The mask has high (7th) bit set in every byte that needs
5594 // conversion and we know that the distance between cases is
5595 // 1 << 5.
5596 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5597 src += sizeof(uintptr_t);
5598 dst += sizeof(uintptr_t);
5599 }
5600#endif
5601 // Process the last few bytes of the input (or the whole input if
5602 // unaligned access is not supported).
5603 while (src < limit) {
5604 char c = *src;
5605 if (lo < c && c < hi) {
5606 c ^= (1 << 5);
5607 changed = true;
5608 }
5609 *dst = c;
5610 ++src;
5611 ++dst;
5612 }
5613#ifdef DEBUG
5614 CheckConvert(saved_dst, saved_src, length, changed);
5615#endif
5616 return changed;
5617 }
5618
5619#ifdef DEBUG
5620 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5621 bool expected_changed = false;
5622 for (int i = 0; i < length; i++) {
5623 if (dst[i] == src[i]) continue;
5624 expected_changed = true;
5625 if (dir == ASCII_TO_LOWER) {
5626 ASSERT('A' <= src[i] && src[i] <= 'Z');
5627 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5628 } else {
5629 ASSERT(dir == ASCII_TO_UPPER);
5630 ASSERT('a' <= src[i] && src[i] <= 'z');
5631 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5632 }
5633 }
5634 ASSERT(expected_changed == changed);
5635 }
5636#endif
5637};
5638
5639
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005640struct ToLowerTraits {
5641 typedef unibrow::ToLowercase UnibrowConverter;
5642
lrn@chromium.org303ada72010-10-27 09:33:13 +00005643 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005644};
5645
5646
5647struct ToUpperTraits {
5648 typedef unibrow::ToUppercase UnibrowConverter;
5649
lrn@chromium.org303ada72010-10-27 09:33:13 +00005650 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005651};
5652
5653} // namespace
5654
5655
5656template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005657MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005658 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005659 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005660 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005661 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005662 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005663 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005664
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005665 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005666 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005667 if (length == 0) return s;
5668
5669 // Simpler handling of ascii strings.
5670 //
5671 // NOTE: This assumes that the upper/lower case of an ascii
5672 // character is also ascii. This is currently the case, but it
5673 // might break in the future if we implement more context and locale
5674 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005675 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005676 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005677 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005678 if (!maybe_o->ToObject(&o)) return maybe_o;
5679 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005680 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005681 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005682 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005683 return has_changed_character ? result : s;
5684 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005685
lrn@chromium.org303ada72010-10-27 09:33:13 +00005686 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005687 { MaybeObject* maybe_answer =
5688 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005689 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5690 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005691 if (answer->IsSmi()) {
5692 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005693 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005694 ConvertCaseHelper(isolate,
5695 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005696 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5697 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005698 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005699 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005700}
5701
5702
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005703RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005704 return ConvertCase<ToLowerTraits>(
5705 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005706}
5707
5708
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005709RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005710 return ConvertCase<ToUpperTraits>(
5711 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005712}
5713
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005714
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005715static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5716 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5717}
5718
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005719
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005720RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005721 NoHandleAllocation ha;
5722 ASSERT(args.length() == 3);
5723
5724 CONVERT_CHECKED(String, s, args[0]);
5725 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5726 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5727
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005728 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005729 int length = s->length();
5730
5731 int left = 0;
5732 if (trimLeft) {
5733 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5734 left++;
5735 }
5736 }
5737
5738 int right = length;
5739 if (trimRight) {
5740 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5741 right--;
5742 }
5743 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005744 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005745}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005746
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005747
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005748void FindAsciiStringIndices(Vector<const char> subject,
5749 char pattern,
5750 ZoneList<int>* indices,
5751 unsigned int limit) {
5752 ASSERT(limit > 0);
5753 // Collect indices of pattern in subject using memchr.
5754 // Stop after finding at most limit values.
5755 const char* subject_start = reinterpret_cast<const char*>(subject.start());
5756 const char* subject_end = subject_start + subject.length();
5757 const char* pos = subject_start;
5758 while (limit > 0) {
5759 pos = reinterpret_cast<const char*>(
5760 memchr(pos, pattern, subject_end - pos));
5761 if (pos == NULL) return;
5762 indices->Add(static_cast<int>(pos - subject_start));
5763 pos++;
5764 limit--;
5765 }
5766}
5767
5768
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005769template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005770void FindStringIndices(Isolate* isolate,
5771 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005772 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005773 ZoneList<int>* indices,
5774 unsigned int limit) {
5775 ASSERT(limit > 0);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005776 // Collect indices of pattern in subject.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005777 // Stop after finding at most limit values.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005778 int pattern_length = pattern.length();
5779 int index = 0;
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005780 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005781 while (limit > 0) {
5782 index = search.Search(subject, index);
5783 if (index < 0) return;
5784 indices->Add(index);
5785 index += pattern_length;
5786 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005787 }
5788}
5789
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005790
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005791RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005792 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005793 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005794 CONVERT_ARG_CHECKED(String, subject, 0);
5795 CONVERT_ARG_CHECKED(String, pattern, 1);
5796 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5797
5798 int subject_length = subject->length();
5799 int pattern_length = pattern->length();
5800 RUNTIME_ASSERT(pattern_length > 0);
5801
5802 // The limit can be very large (0xffffffffu), but since the pattern
5803 // isn't empty, we can never create more parts than ~half the length
5804 // of the subject.
5805
5806 if (!subject->IsFlat()) FlattenString(subject);
5807
5808 static const int kMaxInitialListCapacity = 16;
5809
danno@chromium.org40cb8782011-05-25 07:58:50 +00005810 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005811
5812 // Find (up to limit) indices of separator and end-of-string in subject
5813 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5814 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005815 if (!pattern->IsFlat()) FlattenString(pattern);
5816
5817 // No allocation block.
5818 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005819 AssertNoAllocation nogc;
5820 if (subject->IsAsciiRepresentation()) {
5821 Vector<const char> subject_vector = subject->ToAsciiVector();
5822 if (pattern->IsAsciiRepresentation()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005823 Vector<const char> pattern_vector = pattern->ToAsciiVector();
5824 if (pattern_vector.length() == 1) {
5825 FindAsciiStringIndices(subject_vector,
5826 pattern_vector[0],
5827 &indices,
5828 limit);
5829 } else {
5830 FindStringIndices(isolate,
5831 subject_vector,
5832 pattern_vector,
5833 &indices,
5834 limit);
5835 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005836 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005837 FindStringIndices(isolate,
5838 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005839 pattern->ToUC16Vector(),
5840 &indices,
5841 limit);
5842 }
5843 } else {
5844 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5845 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005846 FindStringIndices(isolate,
5847 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005848 pattern->ToAsciiVector(),
5849 &indices,
5850 limit);
5851 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005852 FindStringIndices(isolate,
5853 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005854 pattern->ToUC16Vector(),
5855 &indices,
5856 limit);
5857 }
5858 }
5859 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005860
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005861 if (static_cast<uint32_t>(indices.length()) < limit) {
5862 indices.Add(subject_length);
5863 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005864
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005865 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005866
5867 // Create JSArray of substrings separated by separator.
5868 int part_count = indices.length();
5869
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005870 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005871 result->set_length(Smi::FromInt(part_count));
5872
5873 ASSERT(result->HasFastElements());
5874
5875 if (part_count == 1 && indices.at(0) == subject_length) {
5876 FixedArray::cast(result->elements())->set(0, *subject);
5877 return *result;
5878 }
5879
5880 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5881 int part_start = 0;
5882 for (int i = 0; i < part_count; i++) {
5883 HandleScope local_loop_handle;
5884 int part_end = indices.at(i);
5885 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00005886 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005887 elements->set(i, *substring);
5888 part_start = part_end + pattern_length;
5889 }
5890
5891 return *result;
5892}
5893
5894
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005895// Copies ascii characters to the given fixed array looking up
5896// one-char strings in the cache. Gives up on the first char that is
5897// not in the cache and fills the remainder with smi zeros. Returns
5898// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005899static int CopyCachedAsciiCharsToArray(Heap* heap,
5900 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005901 FixedArray* elements,
5902 int length) {
5903 AssertNoAllocation nogc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005904 FixedArray* ascii_cache = heap->single_character_string_cache();
5905 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005906 int i;
5907 for (i = 0; i < length; ++i) {
5908 Object* value = ascii_cache->get(chars[i]);
5909 if (value == undefined) break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005910 ASSERT(!heap->InNewSpace(value));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005911 elements->set(i, value, SKIP_WRITE_BARRIER);
5912 }
5913 if (i < length) {
5914 ASSERT(Smi::FromInt(0) == 0);
5915 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5916 }
5917#ifdef DEBUG
5918 for (int j = 0; j < length; ++j) {
5919 Object* element = elements->get(j);
5920 ASSERT(element == Smi::FromInt(0) ||
5921 (element->IsString() && String::cast(element)->LooksValid()));
5922 }
5923#endif
5924 return i;
5925}
5926
5927
5928// Converts a String to JSArray.
5929// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005930RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005931 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005932 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005933 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005934 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005935
5936 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005937 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005938
5939 Handle<FixedArray> elements;
5940 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005941 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005942 { MaybeObject* maybe_obj =
5943 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005944 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5945 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005946 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005947
5948 Vector<const char> chars = s->ToAsciiVector();
5949 // Note, this will initialize all elements (not only the prefix)
5950 // to prevent GC from seeing partially initialized array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005951 int num_copied_from_cache = CopyCachedAsciiCharsToArray(isolate->heap(),
5952 chars.start(),
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005953 *elements,
5954 length);
5955
5956 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005957 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5958 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005959 }
5960 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005961 elements = isolate->factory()->NewFixedArray(length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005962 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005963 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5964 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005965 }
5966 }
5967
5968#ifdef DEBUG
5969 for (int i = 0; i < length; ++i) {
5970 ASSERT(String::cast(elements->get(i))->length() == 1);
5971 }
5972#endif
5973
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005974 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005975}
5976
5977
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005978RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005979 NoHandleAllocation ha;
5980 ASSERT(args.length() == 1);
5981 CONVERT_CHECKED(String, value, args[0]);
5982 return value->ToObject();
5983}
5984
5985
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005986bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005987 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005988 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005989 return char_length == 0;
5990}
5991
5992
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005993RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005994 NoHandleAllocation ha;
5995 ASSERT(args.length() == 1);
5996
5997 Object* number = args[0];
5998 RUNTIME_ASSERT(number->IsNumber());
5999
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006000 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006001}
6002
6003
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006004RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006005 NoHandleAllocation ha;
6006 ASSERT(args.length() == 1);
6007
6008 Object* number = args[0];
6009 RUNTIME_ASSERT(number->IsNumber());
6010
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006011 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006012}
6013
6014
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006015RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006016 NoHandleAllocation ha;
6017 ASSERT(args.length() == 1);
6018
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006019 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006020
6021 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6022 if (number > 0 && number <= Smi::kMaxValue) {
6023 return Smi::FromInt(static_cast<int>(number));
6024 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006025 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006026}
6027
6028
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006029RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006030 NoHandleAllocation ha;
6031 ASSERT(args.length() == 1);
6032
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006033 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006034
6035 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6036 if (number > 0 && number <= Smi::kMaxValue) {
6037 return Smi::FromInt(static_cast<int>(number));
6038 }
6039
6040 double double_value = DoubleToInteger(number);
6041 // Map both -0 and +0 to +0.
6042 if (double_value == 0) double_value = 0;
6043
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006044 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006045}
6046
6047
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006048RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006049 NoHandleAllocation ha;
6050 ASSERT(args.length() == 1);
6051
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006052 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006053 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006054}
6055
6056
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006057RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006058 NoHandleAllocation ha;
6059 ASSERT(args.length() == 1);
6060
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006061 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006062
6063 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6064 if (number > 0 && number <= Smi::kMaxValue) {
6065 return Smi::FromInt(static_cast<int>(number));
6066 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006067 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006068}
6069
6070
ager@chromium.org870a0b62008-11-04 11:43:05 +00006071// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6072// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006073RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006074 NoHandleAllocation ha;
6075 ASSERT(args.length() == 1);
6076
6077 Object* obj = args[0];
6078 if (obj->IsSmi()) {
6079 return obj;
6080 }
6081 if (obj->IsHeapNumber()) {
6082 double value = HeapNumber::cast(obj)->value();
6083 int int_value = FastD2I(value);
6084 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6085 return Smi::FromInt(int_value);
6086 }
6087 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006088 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006089}
6090
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006091
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006092RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006093 NoHandleAllocation ha;
6094 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006095 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006096}
6097
6098
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006099RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006100 NoHandleAllocation ha;
6101 ASSERT(args.length() == 2);
6102
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006103 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6104 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006105 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006106}
6107
6108
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006109RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006110 NoHandleAllocation ha;
6111 ASSERT(args.length() == 2);
6112
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006113 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6114 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006115 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006116}
6117
6118
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006119RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006120 NoHandleAllocation ha;
6121 ASSERT(args.length() == 2);
6122
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006123 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6124 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006125 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006126}
6127
6128
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006129RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006130 NoHandleAllocation ha;
6131 ASSERT(args.length() == 1);
6132
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006133 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006134 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006135}
6136
6137
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006138RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006139 NoHandleAllocation ha;
6140 ASSERT(args.length() == 0);
6141
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006142 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006143}
6144
6145
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006146RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006147 NoHandleAllocation ha;
6148 ASSERT(args.length() == 2);
6149
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006150 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6151 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006152 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006153}
6154
6155
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006156RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006157 NoHandleAllocation ha;
6158 ASSERT(args.length() == 2);
6159
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006160 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6161 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006162
ager@chromium.org3811b432009-10-28 14:53:37 +00006163 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006164 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006165 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006166}
6167
6168
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006169RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006170 NoHandleAllocation ha;
6171 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006172 CONVERT_CHECKED(String, str1, args[0]);
6173 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006174 isolate->counters()->string_add_runtime()->Increment();
6175 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006176}
6177
6178
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006179template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006180static inline void StringBuilderConcatHelper(String* special,
6181 sinkchar* sink,
6182 FixedArray* fixed_array,
6183 int array_length) {
6184 int position = 0;
6185 for (int i = 0; i < array_length; i++) {
6186 Object* element = fixed_array->get(i);
6187 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006188 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006189 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006190 int pos;
6191 int len;
6192 if (encoded_slice > 0) {
6193 // Position and length encoded in one smi.
6194 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6195 len = StringBuilderSubstringLength::decode(encoded_slice);
6196 } else {
6197 // Position and length encoded in two smis.
6198 Object* obj = fixed_array->get(++i);
6199 ASSERT(obj->IsSmi());
6200 pos = Smi::cast(obj)->value();
6201 len = -encoded_slice;
6202 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006203 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006204 sink + position,
6205 pos,
6206 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006207 position += len;
6208 } else {
6209 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006210 int element_length = string->length();
6211 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006212 position += element_length;
6213 }
6214 }
6215}
6216
6217
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006218RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006219 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006220 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006221 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006222 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006223 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006224 return Failure::OutOfMemoryException();
6225 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006226 int array_length = args.smi_at(1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006227 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006228
6229 // This assumption is used by the slice encoding in one or two smis.
6230 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6231
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006232 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006233 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006234 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006235 }
6236 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006237 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006238 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006239 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006240
6241 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006242 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006243 } else if (array_length == 1) {
6244 Object* first = fixed_array->get(0);
6245 if (first->IsString()) return first;
6246 }
6247
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006248 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006249 int position = 0;
6250 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006251 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006252 Object* elt = fixed_array->get(i);
6253 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006254 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006255 int smi_value = Smi::cast(elt)->value();
6256 int pos;
6257 int len;
6258 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006259 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006260 pos = StringBuilderSubstringPosition::decode(smi_value);
6261 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006262 } else {
6263 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006264 len = -smi_value;
6265 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006266 i++;
6267 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006268 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006269 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006270 Object* next_smi = fixed_array->get(i);
6271 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006272 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006273 }
6274 pos = Smi::cast(next_smi)->value();
6275 if (pos < 0) {
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 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006278 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006279 ASSERT(pos >= 0);
6280 ASSERT(len >= 0);
6281 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006282 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006283 }
6284 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006285 } else if (elt->IsString()) {
6286 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006287 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006288 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006289 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006290 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006291 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006292 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006293 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006294 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006295 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006296 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006297 return Failure::OutOfMemoryException();
6298 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006299 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006300 }
6301
6302 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006303 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006304
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006305 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006306 { MaybeObject* maybe_object =
6307 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006308 if (!maybe_object->ToObject(&object)) return maybe_object;
6309 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006310 SeqAsciiString* answer = SeqAsciiString::cast(object);
6311 StringBuilderConcatHelper(special,
6312 answer->GetChars(),
6313 fixed_array,
6314 array_length);
6315 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006316 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006317 { MaybeObject* maybe_object =
6318 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006319 if (!maybe_object->ToObject(&object)) return maybe_object;
6320 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006321 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6322 StringBuilderConcatHelper(special,
6323 answer->GetChars(),
6324 fixed_array,
6325 array_length);
6326 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006327 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006328}
6329
6330
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006331RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006332 NoHandleAllocation ha;
6333 ASSERT(args.length() == 3);
6334 CONVERT_CHECKED(JSArray, array, args[0]);
6335 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006336 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006337 return Failure::OutOfMemoryException();
6338 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006339 int array_length = args.smi_at(1);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006340 CONVERT_CHECKED(String, separator, args[2]);
6341
6342 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006343 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006344 }
6345 FixedArray* fixed_array = FixedArray::cast(array->elements());
6346 if (fixed_array->length() < array_length) {
6347 array_length = fixed_array->length();
6348 }
6349
6350 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006351 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006352 } else if (array_length == 1) {
6353 Object* first = fixed_array->get(0);
6354 if (first->IsString()) return first;
6355 }
6356
6357 int separator_length = separator->length();
6358 int max_nof_separators =
6359 (String::kMaxLength + separator_length - 1) / separator_length;
6360 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006361 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006362 return Failure::OutOfMemoryException();
6363 }
6364 int length = (array_length - 1) * separator_length;
6365 for (int i = 0; i < array_length; i++) {
6366 Object* element_obj = fixed_array->get(i);
6367 if (!element_obj->IsString()) {
6368 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006369 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006370 }
6371 String* element = String::cast(element_obj);
6372 int increment = element->length();
6373 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006374 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006375 return Failure::OutOfMemoryException();
6376 }
6377 length += increment;
6378 }
6379
6380 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006381 { MaybeObject* maybe_object =
6382 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006383 if (!maybe_object->ToObject(&object)) return maybe_object;
6384 }
6385 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6386
6387 uc16* sink = answer->GetChars();
6388#ifdef DEBUG
6389 uc16* end = sink + length;
6390#endif
6391
6392 String* first = String::cast(fixed_array->get(0));
6393 int first_length = first->length();
6394 String::WriteToFlat(first, sink, 0, first_length);
6395 sink += first_length;
6396
6397 for (int i = 1; i < array_length; i++) {
6398 ASSERT(sink + separator_length <= end);
6399 String::WriteToFlat(separator, sink, 0, separator_length);
6400 sink += separator_length;
6401
6402 String* element = String::cast(fixed_array->get(i));
6403 int element_length = element->length();
6404 ASSERT(sink + element_length <= end);
6405 String::WriteToFlat(element, sink, 0, element_length);
6406 sink += element_length;
6407 }
6408 ASSERT(sink == end);
6409
6410 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6411 return answer;
6412}
6413
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006414template <typename Char>
6415static void JoinSparseArrayWithSeparator(FixedArray* elements,
6416 int elements_length,
6417 uint32_t array_length,
6418 String* separator,
6419 Vector<Char> buffer) {
6420 int previous_separator_position = 0;
6421 int separator_length = separator->length();
6422 int cursor = 0;
6423 for (int i = 0; i < elements_length; i += 2) {
6424 int position = NumberToInt32(elements->get(i));
6425 String* string = String::cast(elements->get(i + 1));
6426 int string_length = string->length();
6427 if (string->length() > 0) {
6428 while (previous_separator_position < position) {
6429 String::WriteToFlat<Char>(separator, &buffer[cursor],
6430 0, separator_length);
6431 cursor += separator_length;
6432 previous_separator_position++;
6433 }
6434 String::WriteToFlat<Char>(string, &buffer[cursor],
6435 0, string_length);
6436 cursor += string->length();
6437 }
6438 }
6439 if (separator_length > 0) {
6440 // Array length must be representable as a signed 32-bit number,
6441 // otherwise the total string length would have been too large.
6442 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6443 int last_array_index = static_cast<int>(array_length - 1);
6444 while (previous_separator_position < last_array_index) {
6445 String::WriteToFlat<Char>(separator, &buffer[cursor],
6446 0, separator_length);
6447 cursor += separator_length;
6448 previous_separator_position++;
6449 }
6450 }
6451 ASSERT(cursor <= buffer.length());
6452}
6453
6454
6455RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6456 NoHandleAllocation ha;
6457 ASSERT(args.length() == 3);
6458 CONVERT_CHECKED(JSArray, elements_array, args[0]);
6459 RUNTIME_ASSERT(elements_array->HasFastElements());
6460 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6461 CONVERT_CHECKED(String, separator, args[2]);
6462 // elements_array is fast-mode JSarray of alternating positions
6463 // (increasing order) and strings.
6464 // array_length is length of original array (used to add separators);
6465 // separator is string to put between elements. Assumed to be non-empty.
6466
6467 // Find total length of join result.
6468 int string_length = 0;
6469 bool is_ascii = true;
6470 int max_string_length = SeqAsciiString::kMaxLength;
6471 bool overflow = false;
6472 CONVERT_NUMBER_CHECKED(int, elements_length,
6473 Int32, elements_array->length());
6474 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6475 FixedArray* elements = FixedArray::cast(elements_array->elements());
6476 for (int i = 0; i < elements_length; i += 2) {
6477 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6478 CONVERT_CHECKED(String, string, elements->get(i + 1));
6479 int length = string->length();
6480 if (is_ascii && !string->IsAsciiRepresentation()) {
6481 is_ascii = false;
6482 max_string_length = SeqTwoByteString::kMaxLength;
6483 }
6484 if (length > max_string_length ||
6485 max_string_length - length < string_length) {
6486 overflow = true;
6487 break;
6488 }
6489 string_length += length;
6490 }
6491 int separator_length = separator->length();
6492 if (!overflow && separator_length > 0) {
6493 if (array_length <= 0x7fffffffu) {
6494 int separator_count = static_cast<int>(array_length) - 1;
6495 int remaining_length = max_string_length - string_length;
6496 if ((remaining_length / separator_length) >= separator_count) {
6497 string_length += separator_length * (array_length - 1);
6498 } else {
6499 // Not room for the separators within the maximal string length.
6500 overflow = true;
6501 }
6502 } else {
6503 // Nonempty separator and at least 2^31-1 separators necessary
6504 // means that the string is too large to create.
6505 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6506 overflow = true;
6507 }
6508 }
6509 if (overflow) {
6510 // Throw OutOfMemory exception for creating too large a string.
6511 V8::FatalProcessOutOfMemory("Array join result too large.");
6512 }
6513
6514 if (is_ascii) {
6515 MaybeObject* result_allocation =
6516 isolate->heap()->AllocateRawAsciiString(string_length);
6517 if (result_allocation->IsFailure()) return result_allocation;
6518 SeqAsciiString* result_string =
6519 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6520 JoinSparseArrayWithSeparator<char>(elements,
6521 elements_length,
6522 array_length,
6523 separator,
6524 Vector<char>(result_string->GetChars(),
6525 string_length));
6526 return result_string;
6527 } else {
6528 MaybeObject* result_allocation =
6529 isolate->heap()->AllocateRawTwoByteString(string_length);
6530 if (result_allocation->IsFailure()) return result_allocation;
6531 SeqTwoByteString* result_string =
6532 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6533 JoinSparseArrayWithSeparator<uc16>(elements,
6534 elements_length,
6535 array_length,
6536 separator,
6537 Vector<uc16>(result_string->GetChars(),
6538 string_length));
6539 return result_string;
6540 }
6541}
6542
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006543
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006544RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006545 NoHandleAllocation ha;
6546 ASSERT(args.length() == 2);
6547
6548 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6549 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006550 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006551}
6552
6553
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006554RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006555 NoHandleAllocation ha;
6556 ASSERT(args.length() == 2);
6557
6558 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6559 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006560 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006561}
6562
6563
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006564RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006565 NoHandleAllocation ha;
6566 ASSERT(args.length() == 2);
6567
6568 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6569 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006570 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006571}
6572
6573
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006574RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006575 NoHandleAllocation ha;
6576 ASSERT(args.length() == 1);
6577
6578 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006579 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006580}
6581
6582
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006583RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006584 NoHandleAllocation ha;
6585 ASSERT(args.length() == 2);
6586
6587 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6588 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006589 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006590}
6591
6592
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006593RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006594 NoHandleAllocation ha;
6595 ASSERT(args.length() == 2);
6596
6597 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6598 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006599 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006600}
6601
6602
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006603RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006604 NoHandleAllocation ha;
6605 ASSERT(args.length() == 2);
6606
6607 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6608 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006609 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006610}
6611
6612
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006613RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006614 NoHandleAllocation ha;
6615 ASSERT(args.length() == 2);
6616
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006617 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6618 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006619 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6620 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6621 if (x == y) return Smi::FromInt(EQUAL);
6622 Object* result;
6623 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6624 result = Smi::FromInt(EQUAL);
6625 } else {
6626 result = Smi::FromInt(NOT_EQUAL);
6627 }
6628 return result;
6629}
6630
6631
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006632RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006633 NoHandleAllocation ha;
6634 ASSERT(args.length() == 2);
6635
6636 CONVERT_CHECKED(String, x, args[0]);
6637 CONVERT_CHECKED(String, y, args[1]);
6638
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006639 bool not_equal = !x->Equals(y);
6640 // This is slightly convoluted because the value that signifies
6641 // equality is 0 and inequality is 1 so we have to negate the result
6642 // from String::Equals.
6643 ASSERT(not_equal == 0 || not_equal == 1);
6644 STATIC_CHECK(EQUAL == 0);
6645 STATIC_CHECK(NOT_EQUAL == 1);
6646 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006647}
6648
6649
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006650RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006651 NoHandleAllocation ha;
6652 ASSERT(args.length() == 3);
6653
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006654 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6655 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006656 if (isnan(x) || isnan(y)) return args[2];
6657 if (x == y) return Smi::FromInt(EQUAL);
6658 if (isless(x, y)) return Smi::FromInt(LESS);
6659 return Smi::FromInt(GREATER);
6660}
6661
6662
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006663// Compare two Smis as if they were converted to strings and then
6664// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006665RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006666 NoHandleAllocation ha;
6667 ASSERT(args.length() == 2);
6668
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006669 // Extract the integer values from the Smis.
6670 CONVERT_CHECKED(Smi, x, args[0]);
6671 CONVERT_CHECKED(Smi, y, args[1]);
6672 int x_value = x->value();
6673 int y_value = y->value();
6674
6675 // If the integers are equal so are the string representations.
6676 if (x_value == y_value) return Smi::FromInt(EQUAL);
6677
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006678 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006679 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006680 if (x_value == 0 || y_value == 0)
6681 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006682
ager@chromium.org32912102009-01-16 10:38:43 +00006683 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006684 // smallest because the char code of '-' is less than the char code
6685 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006686
6687 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
6688 // architectures using 32-bit Smis.
6689 uint32_t x_scaled = x_value;
6690 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006691 if (x_value < 0 || y_value < 0) {
6692 if (y_value >= 0) return Smi::FromInt(LESS);
6693 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006694 x_scaled = -x_value;
6695 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006696 }
6697
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006698 static const uint32_t kPowersOf10[] = {
6699 1, 10, 100, 1000, 10*1000, 100*1000,
6700 1000*1000, 10*1000*1000, 100*1000*1000,
6701 1000*1000*1000
6702 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006703
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006704 // If the integers have the same number of decimal digits they can be
6705 // compared directly as the numeric order is the same as the
6706 // lexicographic order. If one integer has fewer digits, it is scaled
6707 // by some power of 10 to have the same number of digits as the longer
6708 // integer. If the scaled integers are equal it means the shorter
6709 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006710
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006711 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
6712 int x_log2 = IntegerLog2(x_scaled);
6713 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
6714 x_log10 -= x_scaled < kPowersOf10[x_log10];
6715
6716 int y_log2 = IntegerLog2(y_scaled);
6717 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
6718 y_log10 -= y_scaled < kPowersOf10[y_log10];
6719
6720 int tie = EQUAL;
6721
6722 if (x_log10 < y_log10) {
6723 // X has fewer digits. We would like to simply scale up X but that
6724 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
6725 // be scaled up to 9_000_000_000. So we scale up by the next
6726 // smallest power and scale down Y to drop one digit. It is OK to
6727 // drop one digit from the longer integer since the final digit is
6728 // past the length of the shorter integer.
6729 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
6730 y_scaled /= 10;
6731 tie = LESS;
6732 } else if (y_log10 < x_log10) {
6733 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
6734 x_scaled /= 10;
6735 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006736 }
6737
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006738 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
6739 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
6740 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006741}
6742
6743
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006744static Object* StringInputBufferCompare(RuntimeState* state,
6745 String* x,
6746 String* y) {
6747 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
6748 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006749 bufx.Reset(x);
6750 bufy.Reset(y);
6751 while (bufx.has_more() && bufy.has_more()) {
6752 int d = bufx.GetNext() - bufy.GetNext();
6753 if (d < 0) return Smi::FromInt(LESS);
6754 else if (d > 0) return Smi::FromInt(GREATER);
6755 }
6756
6757 // x is (non-trivial) prefix of y:
6758 if (bufy.has_more()) return Smi::FromInt(LESS);
6759 // y is prefix of x:
6760 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6761}
6762
6763
6764static Object* FlatStringCompare(String* x, String* y) {
6765 ASSERT(x->IsFlat());
6766 ASSERT(y->IsFlat());
6767 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6768 int prefix_length = x->length();
6769 if (y->length() < prefix_length) {
6770 prefix_length = y->length();
6771 equal_prefix_result = Smi::FromInt(GREATER);
6772 } else if (y->length() > prefix_length) {
6773 equal_prefix_result = Smi::FromInt(LESS);
6774 }
6775 int r;
6776 if (x->IsAsciiRepresentation()) {
6777 Vector<const char> x_chars = x->ToAsciiVector();
6778 if (y->IsAsciiRepresentation()) {
6779 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006780 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006781 } else {
6782 Vector<const uc16> y_chars = y->ToUC16Vector();
6783 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6784 }
6785 } else {
6786 Vector<const uc16> x_chars = x->ToUC16Vector();
6787 if (y->IsAsciiRepresentation()) {
6788 Vector<const char> y_chars = y->ToAsciiVector();
6789 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6790 } else {
6791 Vector<const uc16> y_chars = y->ToUC16Vector();
6792 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6793 }
6794 }
6795 Object* result;
6796 if (r == 0) {
6797 result = equal_prefix_result;
6798 } else {
6799 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6800 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006801 ASSERT(result ==
6802 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006803 return result;
6804}
6805
6806
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006807RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006808 NoHandleAllocation ha;
6809 ASSERT(args.length() == 2);
6810
6811 CONVERT_CHECKED(String, x, args[0]);
6812 CONVERT_CHECKED(String, y, args[1]);
6813
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006814 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006815
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006816 // A few fast case tests before we flatten.
6817 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006818 if (y->length() == 0) {
6819 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006820 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006821 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006822 return Smi::FromInt(LESS);
6823 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006824
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006825 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006826 if (d < 0) return Smi::FromInt(LESS);
6827 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006828
lrn@chromium.org303ada72010-10-27 09:33:13 +00006829 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006830 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006831 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6832 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006833 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006834 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6835 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006836
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006837 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006838 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006839}
6840
6841
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006842RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006843 NoHandleAllocation ha;
6844 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006845 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006846
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006847 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006848 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006849}
6850
6851
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006852RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006853 NoHandleAllocation ha;
6854 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006855 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006856
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006857 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006858 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006859}
6860
6861
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006862RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006863 NoHandleAllocation ha;
6864 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006865 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006866
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006867 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006868 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006869}
6870
6871
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006872static const double kPiDividedBy4 = 0.78539816339744830962;
6873
6874
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006875RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006876 NoHandleAllocation ha;
6877 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006878 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006879
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006880 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6881 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006882 double result;
6883 if (isinf(x) && isinf(y)) {
6884 // Make sure that the result in case of two infinite arguments
6885 // is a multiple of Pi / 4. The sign of the result is determined
6886 // by the first argument (x) and the sign of the second argument
6887 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006888 int multiplier = (x < 0) ? -1 : 1;
6889 if (y < 0) multiplier *= 3;
6890 result = multiplier * kPiDividedBy4;
6891 } else {
6892 result = atan2(x, y);
6893 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006894 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006895}
6896
6897
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006898RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006899 NoHandleAllocation ha;
6900 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006901 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006902
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006903 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006904 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006905}
6906
6907
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006908RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006909 NoHandleAllocation ha;
6910 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006911 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006912
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006913 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006914 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006915}
6916
6917
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006918RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006919 NoHandleAllocation ha;
6920 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006921 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006922
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006923 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006924 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006925}
6926
6927
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006928RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006929 NoHandleAllocation ha;
6930 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006931 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006932
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006933 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006934 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006935}
6936
6937
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006938RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006939 NoHandleAllocation ha;
6940 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006941 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006942
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006943 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006944 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006945}
6946
6947
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006948RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006949 NoHandleAllocation ha;
6950 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006951 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006952
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006953 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006954
6955 // If the second argument is a smi, it is much faster to call the
6956 // custom powi() function than the generic pow().
6957 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006958 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006959 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006960 }
6961
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006962 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006963 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006964}
6965
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006966// Fast version of Math.pow if we know that y is not an integer and
6967// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006968RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006969 NoHandleAllocation ha;
6970 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006971 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6972 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006973 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006974 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006975 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006976 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006977 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006978 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006979 }
6980}
6981
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006982
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006983RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006984 NoHandleAllocation ha;
6985 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006986 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006987
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006988 if (!args[0]->IsHeapNumber()) {
6989 // Must be smi. Return the argument unchanged for all the other types
6990 // to make fuzz-natives test happy.
6991 return args[0];
6992 }
6993
6994 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6995
6996 double value = number->value();
6997 int exponent = number->get_exponent();
6998 int sign = number->get_sign();
6999
danno@chromium.org160a7b02011-04-18 15:51:38 +00007000 if (exponent < -1) {
7001 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7002 if (sign) return isolate->heap()->minus_zero_value();
7003 return Smi::FromInt(0);
7004 }
7005
7006 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7007 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
7008 // agument holds for 32-bit smis).
7009 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007010 return Smi::FromInt(static_cast<int>(value + 0.5));
7011 }
7012
7013 // If the magnitude is big enough, there's no place for fraction part. If we
7014 // try to add 0.5 to this number, 1.0 will be added instead.
7015 if (exponent >= 52) {
7016 return number;
7017 }
7018
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007019 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007020
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007021 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007022 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007023}
7024
7025
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007026RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007027 NoHandleAllocation ha;
7028 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007029 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007030
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007031 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007032 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007033}
7034
7035
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007036RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007037 NoHandleAllocation ha;
7038 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007039 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007040
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007041 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007042 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007043}
7044
7045
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007046RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007047 NoHandleAllocation ha;
7048 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007049 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007050
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007051 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007052 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007053}
7054
7055
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007056static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007057 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7058 181, 212, 243, 273, 304, 334};
7059 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7060 182, 213, 244, 274, 305, 335};
7061
7062 year += month / 12;
7063 month %= 12;
7064 if (month < 0) {
7065 year--;
7066 month += 12;
7067 }
7068
7069 ASSERT(month >= 0);
7070 ASSERT(month < 12);
7071
7072 // year_delta is an arbitrary number such that:
7073 // a) year_delta = -1 (mod 400)
7074 // b) year + year_delta > 0 for years in the range defined by
7075 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7076 // Jan 1 1970. This is required so that we don't run into integer
7077 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007078 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007079 // operations.
7080 static const int year_delta = 399999;
7081 static const int base_day = 365 * (1970 + year_delta) +
7082 (1970 + year_delta) / 4 -
7083 (1970 + year_delta) / 100 +
7084 (1970 + year_delta) / 400;
7085
7086 int year1 = year + year_delta;
7087 int day_from_year = 365 * year1 +
7088 year1 / 4 -
7089 year1 / 100 +
7090 year1 / 400 -
7091 base_day;
7092
7093 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007094 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007095 }
7096
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007097 return day_from_year + day_from_month_leap[month] + day - 1;
7098}
7099
7100
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007101RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007102 NoHandleAllocation ha;
7103 ASSERT(args.length() == 3);
7104
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007105 CONVERT_SMI_ARG_CHECKED(year, 0);
7106 CONVERT_SMI_ARG_CHECKED(month, 1);
7107 CONVERT_SMI_ARG_CHECKED(date, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007108
7109 return Smi::FromInt(MakeDay(year, month, date));
7110}
7111
7112
7113static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7114static const int kDaysIn4Years = 4 * 365 + 1;
7115static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7116static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7117static const int kDays1970to2000 = 30 * 365 + 7;
7118static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7119 kDays1970to2000;
7120static const int kYearsOffset = 400000;
7121
7122static const char kDayInYear[] = {
7123 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7124 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7125 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7126 22, 23, 24, 25, 26, 27, 28,
7127 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7128 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7129 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7130 22, 23, 24, 25, 26, 27, 28, 29, 30,
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, 29, 30,
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, 31,
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,
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, 31,
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,
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
7148 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7149 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7150 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7151 22, 23, 24, 25, 26, 27, 28,
7152 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7153 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7154 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7155 22, 23, 24, 25, 26, 27, 28, 29, 30,
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, 29, 30,
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, 31,
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,
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, 31,
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,
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
7173 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7174 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7175 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7176 22, 23, 24, 25, 26, 27, 28, 29,
7177 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7178 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7179 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7180 22, 23, 24, 25, 26, 27, 28, 29, 30,
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, 30,
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, 31,
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,
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, 31,
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,
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
7198 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7199 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7200 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7201 22, 23, 24, 25, 26, 27, 28,
7202 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7203 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7204 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7205 22, 23, 24, 25, 26, 27, 28, 29, 30,
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, 29, 30,
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, 31,
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,
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, 31,
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,
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
7223static const char kMonthInYear[] = {
7224 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,
7225 0, 0, 0, 0, 0, 0,
7226 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,
7227 1, 1, 1,
7228 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,
7229 2, 2, 2, 2, 2, 2,
7230 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,
7231 3, 3, 3, 3, 3,
7232 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,
7233 4, 4, 4, 4, 4, 4,
7234 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,
7235 5, 5, 5, 5, 5,
7236 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,
7237 6, 6, 6, 6, 6, 6,
7238 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,
7239 7, 7, 7, 7, 7, 7,
7240 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,
7241 8, 8, 8, 8, 8,
7242 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,
7243 9, 9, 9, 9, 9, 9,
7244 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7245 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7246 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7247 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7248
7249 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,
7250 0, 0, 0, 0, 0, 0,
7251 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,
7252 1, 1, 1,
7253 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,
7254 2, 2, 2, 2, 2, 2,
7255 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,
7256 3, 3, 3, 3, 3,
7257 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,
7258 4, 4, 4, 4, 4, 4,
7259 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,
7260 5, 5, 5, 5, 5,
7261 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,
7262 6, 6, 6, 6, 6, 6,
7263 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,
7264 7, 7, 7, 7, 7, 7,
7265 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,
7266 8, 8, 8, 8, 8,
7267 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,
7268 9, 9, 9, 9, 9, 9,
7269 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7270 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7271 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7272 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7273
7274 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,
7275 0, 0, 0, 0, 0, 0,
7276 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,
7277 1, 1, 1, 1,
7278 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,
7279 2, 2, 2, 2, 2, 2,
7280 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,
7281 3, 3, 3, 3, 3,
7282 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,
7283 4, 4, 4, 4, 4, 4,
7284 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,
7285 5, 5, 5, 5, 5,
7286 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,
7287 6, 6, 6, 6, 6, 6,
7288 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,
7289 7, 7, 7, 7, 7, 7,
7290 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,
7291 8, 8, 8, 8, 8,
7292 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,
7293 9, 9, 9, 9, 9, 9,
7294 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7295 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7296 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7297 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7298
7299 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,
7300 0, 0, 0, 0, 0, 0,
7301 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,
7302 1, 1, 1,
7303 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,
7304 2, 2, 2, 2, 2, 2,
7305 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,
7306 3, 3, 3, 3, 3,
7307 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,
7308 4, 4, 4, 4, 4, 4,
7309 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,
7310 5, 5, 5, 5, 5,
7311 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,
7312 6, 6, 6, 6, 6, 6,
7313 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,
7314 7, 7, 7, 7, 7, 7,
7315 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,
7316 8, 8, 8, 8, 8,
7317 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,
7318 9, 9, 9, 9, 9, 9,
7319 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7320 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7321 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7322 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7323
7324
7325// This function works for dates from 1970 to 2099.
7326static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007327 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007328#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007329 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007330#endif
7331
7332 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7333 date %= kDaysIn4Years;
7334
7335 month = kMonthInYear[date];
7336 day = kDayInYear[date];
7337
7338 ASSERT(MakeDay(year, month, day) == save_date);
7339}
7340
7341
7342static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007343 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007344#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007345 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007346#endif
7347
7348 date += kDaysOffset;
7349 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7350 date %= kDaysIn400Years;
7351
7352 ASSERT(MakeDay(year, 0, 1) + date == save_date);
7353
7354 date--;
7355 int yd1 = date / kDaysIn100Years;
7356 date %= kDaysIn100Years;
7357 year += 100 * yd1;
7358
7359 date++;
7360 int yd2 = date / kDaysIn4Years;
7361 date %= kDaysIn4Years;
7362 year += 4 * yd2;
7363
7364 date--;
7365 int yd3 = date / 365;
7366 date %= 365;
7367 year += yd3;
7368
7369 bool is_leap = (!yd1 || yd2) && !yd3;
7370
7371 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007372 ASSERT(is_leap || (date >= 0));
7373 ASSERT((date < 365) || (is_leap && (date < 366)));
7374 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
7375 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
7376 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007377
7378 if (is_leap) {
7379 day = kDayInYear[2*365 + 1 + date];
7380 month = kMonthInYear[2*365 + 1 + date];
7381 } else {
7382 day = kDayInYear[date];
7383 month = kMonthInYear[date];
7384 }
7385
7386 ASSERT(MakeDay(year, month, day) == save_date);
7387}
7388
7389
7390static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007391 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007392 if (date >= 0 && date < 32 * kDaysIn4Years) {
7393 DateYMDFromTimeAfter1970(date, year, month, day);
7394 } else {
7395 DateYMDFromTimeSlow(date, year, month, day);
7396 }
7397}
7398
7399
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007400RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007401 NoHandleAllocation ha;
7402 ASSERT(args.length() == 2);
7403
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007404 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007405 CONVERT_CHECKED(JSArray, res_array, args[1]);
7406
7407 int year, month, day;
7408 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7409
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007410 RUNTIME_ASSERT(res_array->elements()->map() ==
7411 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007412 FixedArray* elms = FixedArray::cast(res_array->elements());
7413 RUNTIME_ASSERT(elms->length() == 3);
7414
7415 elms->set(0, Smi::FromInt(year));
7416 elms->set(1, Smi::FromInt(month));
7417 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007418
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007419 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007420}
7421
7422
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007423RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007424 HandleScope scope(isolate);
7425 ASSERT(args.length() == 3);
7426
7427 Handle<JSFunction> callee = args.at<JSFunction>(0);
7428 Object** parameters = reinterpret_cast<Object**>(args[1]);
7429 const int argument_count = Smi::cast(args[2])->value();
7430
7431 Handle<JSObject> result =
7432 isolate->factory()->NewArgumentsObject(callee, argument_count);
7433 // Allocate the elements if needed.
7434 int parameter_count = callee->shared()->formal_parameter_count();
7435 if (argument_count > 0) {
7436 if (parameter_count > 0) {
7437 int mapped_count = Min(argument_count, parameter_count);
7438 Handle<FixedArray> parameter_map =
7439 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7440 parameter_map->set_map(
7441 isolate->heap()->non_strict_arguments_elements_map());
7442
7443 Handle<Map> old_map(result->map());
7444 Handle<Map> new_map =
7445 isolate->factory()->CopyMapDropTransitions(old_map);
7446 new_map->set_elements_kind(JSObject::NON_STRICT_ARGUMENTS_ELEMENTS);
7447
7448 result->set_map(*new_map);
7449 result->set_elements(*parameter_map);
7450
7451 // Store the context and the arguments array at the beginning of the
7452 // parameter map.
7453 Handle<Context> context(isolate->context());
7454 Handle<FixedArray> arguments =
7455 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7456 parameter_map->set(0, *context);
7457 parameter_map->set(1, *arguments);
7458
7459 // Loop over the actual parameters backwards.
7460 int index = argument_count - 1;
7461 while (index >= mapped_count) {
7462 // These go directly in the arguments array and have no
7463 // corresponding slot in the parameter map.
7464 arguments->set(index, *(parameters - index - 1));
7465 --index;
7466 }
7467
7468 ScopeInfo<> scope_info(callee->shared()->scope_info());
7469 while (index >= 0) {
7470 // Detect duplicate names to the right in the parameter list.
7471 Handle<String> name = scope_info.parameter_name(index);
7472 int context_slot_count = scope_info.number_of_context_slots();
7473 bool duplicate = false;
7474 for (int j = index + 1; j < parameter_count; ++j) {
7475 if (scope_info.parameter_name(j).is_identical_to(name)) {
7476 duplicate = true;
7477 break;
7478 }
7479 }
7480
7481 if (duplicate) {
7482 // This goes directly in the arguments array with a hole in the
7483 // parameter map.
7484 arguments->set(index, *(parameters - index - 1));
7485 parameter_map->set_the_hole(index + 2);
7486 } else {
7487 // The context index goes in the parameter map with a hole in the
7488 // arguments array.
7489 int context_index = -1;
7490 for (int j = Context::MIN_CONTEXT_SLOTS;
7491 j < context_slot_count;
7492 ++j) {
7493 if (scope_info.context_slot_name(j).is_identical_to(name)) {
7494 context_index = j;
7495 break;
7496 }
7497 }
7498 ASSERT(context_index >= 0);
7499 arguments->set_the_hole(index);
7500 parameter_map->set(index + 2, Smi::FromInt(context_index));
7501 }
7502
7503 --index;
7504 }
7505 } else {
7506 // If there is no aliasing, the arguments object elements are not
7507 // special in any way.
7508 Handle<FixedArray> elements =
7509 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7510 result->set_elements(*elements);
7511 for (int i = 0; i < argument_count; ++i) {
7512 elements->set(i, *(parameters - i - 1));
7513 }
7514 }
7515 }
7516 return *result;
7517}
7518
7519
7520RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007521 NoHandleAllocation ha;
7522 ASSERT(args.length() == 3);
7523
7524 JSFunction* callee = JSFunction::cast(args[0]);
7525 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007526 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007527
lrn@chromium.org303ada72010-10-27 09:33:13 +00007528 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007529 { MaybeObject* maybe_result =
7530 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007531 if (!maybe_result->ToObject(&result)) return maybe_result;
7532 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007533 // Allocate the elements if needed.
7534 if (length > 0) {
7535 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007536 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007537 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007538 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7539 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007540
7541 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007542 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007543 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007544 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007545
7546 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007547 for (int i = 0; i < length; i++) {
7548 array->set(i, *--parameters, mode);
7549 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007550 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007551 }
7552 return result;
7553}
7554
7555
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007556RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007557 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007558 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007559 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007560 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007561 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007562
whesse@chromium.org7b260152011-06-20 15:33:18 +00007563 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007564 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007565 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007566 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007567 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7568 context,
7569 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007570 return *result;
7571}
7572
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007573
7574static SmartPointer<Object**> GetNonBoundArguments(int bound_argc,
7575 int* total_argc) {
7576 // Find frame containing arguments passed to the caller.
7577 JavaScriptFrameIterator it;
7578 JavaScriptFrame* frame = it.frame();
7579 List<JSFunction*> functions(2);
7580 frame->GetFunctions(&functions);
7581 if (functions.length() > 1) {
7582 int inlined_frame_index = functions.length() - 1;
7583 JSFunction* inlined_function = functions[inlined_frame_index];
7584 int args_count = inlined_function->shared()->formal_parameter_count();
7585 ScopedVector<SlotRef> args_slots(args_count);
7586 SlotRef::ComputeSlotMappingForArguments(frame,
7587 inlined_frame_index,
7588 &args_slots);
7589
7590 *total_argc = bound_argc + args_count;
7591 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7592 for (int i = 0; i < args_count; i++) {
7593 Handle<Object> val = args_slots[i].GetValue();
7594 param_data[bound_argc + i] = val.location();
7595 }
7596 return param_data;
7597 } else {
7598 it.AdvanceToArgumentsFrame();
7599 frame = it.frame();
7600 int args_count = frame->ComputeParametersCount();
7601
7602 *total_argc = bound_argc + args_count;
7603 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7604 for (int i = 0; i < args_count; i++) {
7605 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7606 param_data[bound_argc + i] = val.location();
7607 }
7608 return param_data;
7609 }
7610}
7611
7612
7613RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007614 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007615 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007616 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007617 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007618
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007619 // Second argument is either null or an array of bound arguments.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007620 Handle<FixedArray> bound_args;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007621 int bound_argc = 0;
7622 if (!args[1]->IsNull()) {
7623 CONVERT_ARG_CHECKED(JSArray, params, 1);
7624 RUNTIME_ASSERT(params->HasFastElements());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007625 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007626 bound_argc = Smi::cast(params->length())->value();
7627 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007628
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007629 int total_argc = 0;
7630 SmartPointer<Object**> param_data =
7631 GetNonBoundArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007632 for (int i = 0; i < bound_argc; i++) {
7633 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007634 param_data[i] = val.location();
7635 }
7636
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007637 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007638 Handle<Object> result =
7639 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007640 if (exception) {
7641 return Failure::Exception();
7642 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007643
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007644 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007645 return *result;
7646}
7647
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007648
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007649static void TrySettingInlineConstructStub(Isolate* isolate,
7650 Handle<JSFunction> function) {
7651 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007652 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007653 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007654 }
7655 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007656 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00007657 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007658 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007659 function->shared()->set_construct_stub(
7660 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007661 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007662 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007663}
7664
7665
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007666RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007667 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007668 ASSERT(args.length() == 1);
7669
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007670 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007671
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007672 // If the constructor isn't a proper function we throw a type error.
7673 if (!constructor->IsJSFunction()) {
7674 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7675 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007676 isolate->factory()->NewTypeError("not_constructor", arguments);
7677 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007678 }
7679
7680 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007681
7682 // If function should not have prototype, construction is not allowed. In this
7683 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00007684 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007685 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7686 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007687 isolate->factory()->NewTypeError("not_constructor", arguments);
7688 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007689 }
7690
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007691#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007692 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007693 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007694 if (debug->StepInActive()) {
7695 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007696 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007697#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007698
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007699 if (function->has_initial_map()) {
7700 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007701 // The 'Function' function ignores the receiver object when
7702 // called using 'new' and creates a new JSFunction object that
7703 // is returned. The receiver object is only used for error
7704 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007705 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007706 // allocate JSFunctions since it does not properly initialize
7707 // the shared part of the function. Since the receiver is
7708 // ignored anyway, we use the global object as the receiver
7709 // instead of a new JSFunction object. This way, errors are
7710 // reported the same way whether or not 'Function' is called
7711 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007712 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007713 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007714 }
7715
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007716 // The function should be compiled for the optimization hints to be
7717 // available. We cannot use EnsureCompiled because that forces a
7718 // compilation through the shared function info which makes it
7719 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007720 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007721 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007722
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007723 if (!function->has_initial_map() &&
7724 shared->IsInobjectSlackTrackingInProgress()) {
7725 // The tracking is already in progress for another function. We can only
7726 // track one initial_map at a time, so we force the completion before the
7727 // function is called as a constructor for the first time.
7728 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007729 }
7730
7731 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007732 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7733 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007734 // Delay setting the stub if inobject slack tracking is in progress.
7735 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007736 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007737 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007738
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007739 isolate->counters()->constructed_objects()->Increment();
7740 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007741
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007742 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007743}
7744
7745
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007746RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007747 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007748 ASSERT(args.length() == 1);
7749
7750 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7751 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007752 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007753
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007754 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007755}
7756
7757
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007758RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007759 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007760 ASSERT(args.length() == 1);
7761
7762 Handle<JSFunction> function = args.at<JSFunction>(0);
7763#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007764 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007765 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007766 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007767 PrintF("]\n");
7768 }
7769#endif
7770
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007771 // Compile the target function. Here we compile using CompileLazyInLoop in
7772 // order to get the optimized version. This helps code like delta-blue
7773 // that calls performance-critical routines through constructors. A
7774 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
7775 // direct call. Since the in-loop tracking takes place through CallICs
7776 // this means that things called through constructors are never known to
7777 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007778 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007779 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007780 return Failure::Exception();
7781 }
7782
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007783 // All done. Return the compiled code.
7784 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007785 return function->code();
7786}
7787
7788
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007789RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007790 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007791 ASSERT(args.length() == 1);
7792 Handle<JSFunction> function = args.at<JSFunction>(0);
7793 // If the function is not optimizable or debugger is active continue using the
7794 // code from the full compiler.
7795 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007796 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007797 if (FLAG_trace_opt) {
7798 PrintF("[failed to optimize ");
7799 function->PrintName();
7800 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7801 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007802 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007803 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007804 function->ReplaceCode(function->shared()->code());
7805 return function->code();
7806 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007807 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007808 return function->code();
7809 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007810 if (FLAG_trace_opt) {
7811 PrintF("[failed to optimize ");
7812 function->PrintName();
7813 PrintF(": optimized compilation failed]\n");
7814 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007815 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007816 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007817}
7818
7819
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007820RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007821 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007822 ASSERT(args.length() == 1);
7823 RUNTIME_ASSERT(args[0]->IsSmi());
7824 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007825 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007826 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
7827 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007828 int frames = deoptimizer->output_count();
7829
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007830 deoptimizer->MaterializeHeapNumbers();
7831 delete deoptimizer;
7832
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007833 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007834 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007835 for (int i = 0; i < frames - 1; i++) it.Advance();
7836 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007837
7838 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007839 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007840 Handle<Object> arguments;
7841 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007842 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007843 if (arguments.is_null()) {
7844 // FunctionGetArguments can't throw an exception, so cast away the
7845 // doubt with an assert.
7846 arguments = Handle<Object>(
7847 Accessors::FunctionGetArguments(*function,
7848 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007849 ASSERT(*arguments != isolate->heap()->null_value());
7850 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007851 }
7852 frame->SetExpression(i, *arguments);
7853 }
7854 }
7855
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007856 if (type == Deoptimizer::EAGER) {
7857 RUNTIME_ASSERT(function->IsOptimized());
7858 } else {
7859 RUNTIME_ASSERT(!function->IsOptimized());
7860 }
7861
7862 // Avoid doing too much work when running with --always-opt and keep
7863 // the optimized code around.
7864 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007865 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007866 }
7867
7868 // Count the number of optimized activations of the function.
7869 int activations = 0;
7870 while (!it.done()) {
7871 JavaScriptFrame* frame = it.frame();
7872 if (frame->is_optimized() && frame->function() == *function) {
7873 activations++;
7874 }
7875 it.Advance();
7876 }
7877
7878 // TODO(kasperl): For now, we cannot support removing the optimized
7879 // code when we have recursive invocations of the same function.
7880 if (activations == 0) {
7881 if (FLAG_trace_deopt) {
7882 PrintF("[removing optimized code for: ");
7883 function->PrintName();
7884 PrintF("]\n");
7885 }
7886 function->ReplaceCode(function->shared()->code());
7887 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007888 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007889}
7890
7891
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007892RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007893 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007894 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007895 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007896}
7897
7898
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007899RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007900 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007901 ASSERT(args.length() == 1);
7902 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007903 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007904
7905 Deoptimizer::DeoptimizeFunction(*function);
7906
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007907 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007908}
7909
7910
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007911RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
7912#if defined(USE_SIMULATOR)
7913 return isolate->heap()->true_value();
7914#else
7915 return isolate->heap()->false_value();
7916#endif
7917}
7918
7919
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00007920RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
7921 HandleScope scope(isolate);
7922 ASSERT(args.length() == 1);
7923 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7924 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
7925 function->MarkForLazyRecompilation();
7926 return isolate->heap()->undefined_value();
7927}
7928
7929
lrn@chromium.org1c092762011-05-09 09:42:16 +00007930RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
7931 HandleScope scope(isolate);
7932 ASSERT(args.length() == 1);
7933 if (!V8::UseCrankshaft()) {
7934 return Smi::FromInt(4); // 4 == "never".
7935 }
7936 if (FLAG_always_opt) {
7937 return Smi::FromInt(3); // 3 == "always".
7938 }
7939 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7940 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
7941 : Smi::FromInt(2); // 2 == "no".
7942}
7943
7944
7945RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
7946 HandleScope scope(isolate);
7947 ASSERT(args.length() == 1);
7948 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7949 return Smi::FromInt(function->shared()->opt_count());
7950}
7951
7952
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007953RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007954 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007955 ASSERT(args.length() == 1);
7956 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7957
7958 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00007959 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007960
7961 // We have hit a back edge in an unoptimized frame for a function that was
7962 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007963 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007964 // Keep track of whether we've succeeded in optimizing.
7965 bool succeeded = unoptimized->optimizable();
7966 if (succeeded) {
7967 // If we are trying to do OSR when there are already optimized
7968 // activations of the function, it means (a) the function is directly or
7969 // indirectly recursive and (b) an optimized invocation has been
7970 // deoptimized so that we are currently in an unoptimized activation.
7971 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007972 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007973 while (succeeded && !it.done()) {
7974 JavaScriptFrame* frame = it.frame();
7975 succeeded = !frame->is_optimized() || frame->function() != *function;
7976 it.Advance();
7977 }
7978 }
7979
7980 int ast_id = AstNode::kNoNumber;
7981 if (succeeded) {
7982 // The top JS function is this one, the PC is somewhere in the
7983 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007984 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007985 JavaScriptFrame* frame = it.frame();
7986 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007987 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007988 ASSERT(unoptimized->contains(frame->pc()));
7989
7990 // Use linear search of the unoptimized code's stack check table to find
7991 // the AST id matching the PC.
7992 Address start = unoptimized->instruction_start();
7993 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007994 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007995 uint32_t table_length = Memory::uint32_at(table_cursor);
7996 table_cursor += kIntSize;
7997 for (unsigned i = 0; i < table_length; ++i) {
7998 // Table entries are (AST id, pc offset) pairs.
7999 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8000 if (pc_offset == target_pc_offset) {
8001 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8002 break;
8003 }
8004 table_cursor += 2 * kIntSize;
8005 }
8006 ASSERT(ast_id != AstNode::kNoNumber);
8007 if (FLAG_trace_osr) {
8008 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8009 function->PrintName();
8010 PrintF("]\n");
8011 }
8012
8013 // Try to compile the optimized code. A true return value from
8014 // CompileOptimized means that compilation succeeded, not necessarily
8015 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008016 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
8017 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008018 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8019 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008020 if (data->OsrPcOffset()->value() >= 0) {
8021 if (FLAG_trace_osr) {
8022 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008023 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008024 }
8025 ASSERT(data->OsrAstId()->value() == ast_id);
8026 } else {
8027 // We may never generate the desired OSR entry if we emit an
8028 // early deoptimize.
8029 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008030 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008031 } else {
8032 succeeded = false;
8033 }
8034 }
8035
8036 // Revert to the original stack checks in the original unoptimized code.
8037 if (FLAG_trace_osr) {
8038 PrintF("[restoring original stack checks in ");
8039 function->PrintName();
8040 PrintF("]\n");
8041 }
8042 StackCheckStub check_stub;
8043 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008044 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008045 Deoptimizer::RevertStackCheckCode(*unoptimized,
8046 *check_code,
8047 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008048
8049 // Allow OSR only at nesting level zero again.
8050 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8051
8052 // If the optimization attempt succeeded, return the AST id tagged as a
8053 // smi. This tells the builtin that we need to translate the unoptimized
8054 // frame to an optimized one.
8055 if (succeeded) {
8056 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8057 return Smi::FromInt(ast_id);
8058 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008059 if (function->IsMarkedForLazyRecompilation()) {
8060 function->ReplaceCode(function->shared()->code());
8061 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008062 return Smi::FromInt(-1);
8063 }
8064}
8065
8066
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008067RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008068 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008069 ASSERT(args.length() == 1);
8070 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8071 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8072}
8073
8074
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008075RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008076 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008077 ASSERT(args.length() == 1);
8078 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8079 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8080}
8081
8082
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008083RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008084 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008085 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008086
kasper.lund7276f142008-07-30 08:49:36 +00008087 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00008088 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008089 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008090 { MaybeObject* maybe_result =
8091 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008092 if (!maybe_result->ToObject(&result)) return maybe_result;
8093 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008094
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008095 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008096
kasper.lund7276f142008-07-30 08:49:36 +00008097 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008098}
8099
lrn@chromium.org303ada72010-10-27 09:33:13 +00008100
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008101RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8102 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008103 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008104 JSObject* extension_object;
8105 if (args[0]->IsJSObject()) {
8106 extension_object = JSObject::cast(args[0]);
8107 } else {
8108 // Convert the object to a proper JavaScript object.
8109 MaybeObject* maybe_js_object = args[0]->ToObject();
8110 if (!maybe_js_object->To(&extension_object)) {
8111 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8112 HandleScope scope(isolate);
8113 Handle<Object> handle = args.at<Object>(0);
8114 Handle<Object> result =
8115 isolate->factory()->NewTypeError("with_expression",
8116 HandleVector(&handle, 1));
8117 return isolate->Throw(*result);
8118 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008119 return maybe_js_object;
8120 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008121 }
8122 }
8123
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008124 JSFunction* function;
8125 if (args[1]->IsSmi()) {
8126 // A smi sentinel indicates a context nested inside global code rather
8127 // than some function. There is a canonical empty function that can be
8128 // gotten from the global context.
8129 function = isolate->context()->global_context()->closure();
8130 } else {
8131 function = JSFunction::cast(args[1]);
8132 }
8133
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008134 Context* context;
8135 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008136 isolate->heap()->AllocateWithContext(function,
8137 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008138 extension_object);
8139 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008140 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008141 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008142}
8143
8144
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008145RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008146 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008147 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008148 String* name = String::cast(args[0]);
8149 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008150 JSFunction* function;
8151 if (args[2]->IsSmi()) {
8152 // A smi sentinel indicates a context nested inside global code rather
8153 // than some function. There is a canonical empty function that can be
8154 // gotten from the global context.
8155 function = isolate->context()->global_context()->closure();
8156 } else {
8157 function = JSFunction::cast(args[2]);
8158 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008159 Context* context;
8160 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008161 isolate->heap()->AllocateCatchContext(function,
8162 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008163 name,
8164 thrown_object);
8165 if (!maybe_context->To(&context)) return maybe_context;
8166 isolate->set_context(context);
8167 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008168}
8169
8170
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008171RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008172 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008173 ASSERT(args.length() == 2);
8174
8175 CONVERT_ARG_CHECKED(Context, context, 0);
8176 CONVERT_ARG_CHECKED(String, name, 1);
8177
8178 int index;
8179 PropertyAttributes attributes;
8180 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008181 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008182
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008183 // If the slot was not found the result is true.
8184 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008185 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008186 }
8187
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008188 // If the slot was found in a context, it should be DONT_DELETE.
8189 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008190 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008191 }
8192
8193 // The slot was found in a JSObject, either a context extension object,
8194 // the global object, or an arguments object. Try to delete it
8195 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
8196 // which allows deleting all parameters in functions that mention
8197 // 'arguments', we do this even for the case of slots found on an
8198 // arguments object. The slot was found on an arguments object if the
8199 // index is non-negative.
8200 Handle<JSObject> object = Handle<JSObject>::cast(holder);
8201 if (index >= 0) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008202 return object->DeleteElement(index, JSReceiver::NORMAL_DELETION);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008203 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008204 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008205 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008206}
8207
8208
ager@chromium.orga1645e22009-09-09 19:27:10 +00008209// A mechanism to return a pair of Object pointers in registers (if possible).
8210// How this is achieved is calling convention-dependent.
8211// All currently supported x86 compiles uses calling conventions that are cdecl
8212// variants where a 64-bit value is returned in two 32-bit registers
8213// (edx:eax on ia32, r1:r0 on ARM).
8214// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8215// In Win64 calling convention, a struct of two pointers is returned in memory,
8216// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008217#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008218struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008219 MaybeObject* x;
8220 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008221};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008222
lrn@chromium.org303ada72010-10-27 09:33:13 +00008223static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008224 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008225 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8226 // In Win64 they are assigned to a hidden first argument.
8227 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008228}
8229#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008230typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008231static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008232 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008233 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008234}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008235#endif
8236
8237
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008238static inline MaybeObject* Unhole(Heap* heap,
8239 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008240 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008241 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8242 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008243 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008244}
8245
8246
danno@chromium.org40cb8782011-05-25 07:58:50 +00008247static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8248 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008249 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008250 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008251 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008252 JSFunction* context_extension_function =
8253 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008254 // If the holder isn't a context extension object, we just return it
8255 // as the receiver. This allows arguments objects to be used as
8256 // receivers, but only if they are put in the context scope chain
8257 // explicitly via a with-statement.
8258 Object* constructor = holder->map()->constructor();
8259 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008260 // Fall back to using the global object as the implicit receiver if
8261 // the property turns out to be a local variable allocated in a
8262 // context extension object - introduced via eval. Implicit global
8263 // receivers are indicated with the hole value.
8264 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008265}
8266
8267
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008268static ObjectPair LoadContextSlotHelper(Arguments args,
8269 Isolate* isolate,
8270 bool throw_error) {
8271 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008272 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008273
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008274 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008275 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008276 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008277 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008278 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008279
8280 int index;
8281 PropertyAttributes attributes;
8282 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008283 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008284
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008285 // If the index is non-negative, the slot has been found in a local
8286 // variable or a parameter. Read it from the context object or the
8287 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008288 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008289 // If the "property" we were looking for is a local variable or an
8290 // argument in a context, the receiver is the global object; see
8291 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008292 //
8293 // Use the hole as the receiver to signal that the receiver is
8294 // implicit and that the global receiver should be used.
8295 Handle<Object> receiver = isolate->factory()->the_hole_value();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008296 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008297 ? Context::cast(*holder)->get(index)
8298 : JSObject::cast(*holder)->GetElement(index);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008299 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008300 }
8301
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008302 // If the holder is found, we read the property from it.
8303 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008304 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008305 JSObject* object = JSObject::cast(*holder);
danno@chromium.org40cb8782011-05-25 07:58:50 +00008306 Object* receiver;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008307 if (object->IsGlobalObject()) {
8308 receiver = GlobalObject::cast(object)->global_receiver();
8309 } else if (context->is_exception_holder(*holder)) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008310 // Use the hole as the receiver to signal that the receiver is
8311 // implicit and that the global receiver should be used.
8312 receiver = isolate->heap()->the_hole_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008313 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008314 receiver = ComputeReceiverForNonGlobal(isolate, object);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008315 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008316
8317 // GetProperty below can cause GC.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008318 Handle<Object> receiver_handle(receiver);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008319
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008320 // No need to unhole the value here. This is taken care of by the
8321 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008322 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008323 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008324 }
8325
8326 if (throw_error) {
8327 // The property doesn't exist - throw exception.
8328 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008329 isolate->factory()->NewReferenceError("not_defined",
8330 HandleVector(&name, 1));
8331 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008332 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008333 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008334 return MakePair(isolate->heap()->undefined_value(),
8335 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008336 }
8337}
8338
8339
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008340RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008341 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008342}
8343
8344
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008345RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008346 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008347}
8348
8349
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008350RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008351 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008352 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008353
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008354 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008355 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008356 CONVERT_ARG_CHECKED(String, name, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008357 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008358 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
8359 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008360 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008361
8362 int index;
8363 PropertyAttributes attributes;
8364 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008365 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008366
8367 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008368 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008369 // Ignore if read_only variable.
8370 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008371 // Context is a fixed array and set cannot fail.
8372 Context::cast(*holder)->set(index, *value);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008373 } else if (strict_mode == kStrictMode) {
8374 // Setting read only property in strict mode.
8375 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008376 isolate->factory()->NewTypeError("strict_cannot_assign",
8377 HandleVector(&name, 1));
8378 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008379 }
8380 } else {
8381 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008382 Handle<Object> result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008383 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008384 if (result.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008385 ASSERT(isolate->has_pending_exception());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008386 return Failure::Exception();
8387 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008388 }
8389 return *value;
8390 }
8391
8392 // Slow case: The property is not in a FixedArray context.
8393 // It is either in an JSObject extension context or it was not found.
8394 Handle<JSObject> context_ext;
8395
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008396 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008397 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008398 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008399 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008400 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008401 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008402
8403 if (strict_mode == kStrictMode) {
8404 // Throw in strict mode (assignment to undefined variable).
8405 Handle<Object> error =
8406 isolate->factory()->NewReferenceError(
8407 "not_defined", HandleVector(&name, 1));
8408 return isolate->Throw(*error);
8409 }
8410 // In non-strict mode, the property is stored in the global context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008411 attributes = NONE;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008412 context_ext = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008413 }
8414
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008415 // Set the property, but ignore if read_only variable on the context
8416 // extension object itself.
8417 if ((attributes & READ_ONLY) == 0 ||
8418 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008419 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008420 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008421 SetProperty(context_ext, name, value, NONE, strict_mode));
8422 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008423 // Setting read only property in strict mode.
8424 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008425 isolate->factory()->NewTypeError(
8426 "strict_cannot_assign", HandleVector(&name, 1));
8427 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008428 }
8429 return *value;
8430}
8431
8432
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008433RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008434 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008435 ASSERT(args.length() == 1);
8436
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008437 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008438}
8439
8440
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008441RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
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->ReThrow(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_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008450 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008451 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008452}
8453
8454
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008455RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008456 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008457 ASSERT(args.length() == 1);
8458
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008459 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008460 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008461 isolate->factory()->NewReferenceError("not_defined",
8462 HandleVector(&name, 1));
8463 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008464}
8465
8466
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008467RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008468 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008469
8470 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008471 if (isolate->stack_guard()->IsStackOverflow()) {
8472 NoHandleAllocation na;
8473 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008474 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008475
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008476 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008477}
8478
8479
8480// NOTE: These PrintXXX functions are defined for all builds (not just
8481// DEBUG builds) because we may want to be able to trace function
8482// calls in all modes.
8483static void PrintString(String* str) {
8484 // not uncommon to have empty strings
8485 if (str->length() > 0) {
8486 SmartPointer<char> s =
8487 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
8488 PrintF("%s", *s);
8489 }
8490}
8491
8492
8493static void PrintObject(Object* obj) {
8494 if (obj->IsSmi()) {
8495 PrintF("%d", Smi::cast(obj)->value());
8496 } else if (obj->IsString() || obj->IsSymbol()) {
8497 PrintString(String::cast(obj));
8498 } else if (obj->IsNumber()) {
8499 PrintF("%g", obj->Number());
8500 } else if (obj->IsFailure()) {
8501 PrintF("<failure>");
8502 } else if (obj->IsUndefined()) {
8503 PrintF("<undefined>");
8504 } else if (obj->IsNull()) {
8505 PrintF("<null>");
8506 } else if (obj->IsTrue()) {
8507 PrintF("<true>");
8508 } else if (obj->IsFalse()) {
8509 PrintF("<false>");
8510 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008511 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008512 }
8513}
8514
8515
8516static int StackSize() {
8517 int n = 0;
8518 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8519 return n;
8520}
8521
8522
8523static void PrintTransition(Object* result) {
8524 // indentation
8525 { const int nmax = 80;
8526 int n = StackSize();
8527 if (n <= nmax)
8528 PrintF("%4d:%*s", n, n, "");
8529 else
8530 PrintF("%4d:%*s", n, nmax, "...");
8531 }
8532
8533 if (result == NULL) {
8534 // constructor calls
8535 JavaScriptFrameIterator it;
8536 JavaScriptFrame* frame = it.frame();
8537 if (frame->IsConstructor()) PrintF("new ");
8538 // function name
8539 Object* fun = frame->function();
8540 if (fun->IsJSFunction()) {
8541 PrintObject(JSFunction::cast(fun)->shared()->name());
8542 } else {
8543 PrintObject(fun);
8544 }
8545 // function arguments
8546 // (we are intentionally only printing the actually
8547 // supplied parameters, not all parameters required)
8548 PrintF("(this=");
8549 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008550 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008551 for (int i = 0; i < length; i++) {
8552 PrintF(", ");
8553 PrintObject(frame->GetParameter(i));
8554 }
8555 PrintF(") {\n");
8556
8557 } else {
8558 // function result
8559 PrintF("} -> ");
8560 PrintObject(result);
8561 PrintF("\n");
8562 }
8563}
8564
8565
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008566RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008567 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008568 NoHandleAllocation ha;
8569 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008570 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008571}
8572
8573
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008574RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008575 NoHandleAllocation ha;
8576 PrintTransition(args[0]);
8577 return args[0]; // return TOS
8578}
8579
8580
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008581RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008582 NoHandleAllocation ha;
8583 ASSERT(args.length() == 1);
8584
8585#ifdef DEBUG
8586 if (args[0]->IsString()) {
8587 // If we have a string, assume it's a code "marker"
8588 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008589 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008590 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008591 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8592 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008593 } else {
8594 PrintF("DebugPrint: ");
8595 }
8596 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008597 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008598 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008599 HeapObject::cast(args[0])->map()->Print();
8600 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008601#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008602 // ShortPrint is available in release mode. Print is not.
8603 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008604#endif
8605 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00008606 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008607
8608 return args[0]; // return TOS
8609}
8610
8611
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008612RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008613 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008614 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008615 isolate->PrintStack();
8616 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008617}
8618
8619
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008620RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008621 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008622 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008623
8624 // According to ECMA-262, section 15.9.1, page 117, the precision of
8625 // the number in a Date object representing a particular instant in
8626 // time is milliseconds. Therefore, we floor the result of getting
8627 // the OS time.
8628 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008629 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008630}
8631
8632
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008633RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008634 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008635 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008636
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008637 CONVERT_ARG_CHECKED(String, str, 0);
8638 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008639
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008640 CONVERT_ARG_CHECKED(JSArray, output, 1);
8641 RUNTIME_ASSERT(output->HasFastElements());
8642
8643 AssertNoAllocation no_allocation;
8644
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008645 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008646 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
8647 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008648 if (str->IsAsciiRepresentation()) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008649 result = DateParser::Parse(str->ToAsciiVector(),
8650 output_array,
8651 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008652 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008653 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008654 result = DateParser::Parse(str->ToUC16Vector(),
8655 output_array,
8656 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008657 }
8658
8659 if (result) {
8660 return *output;
8661 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008662 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008663 }
8664}
8665
8666
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008667RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008668 NoHandleAllocation ha;
8669 ASSERT(args.length() == 1);
8670
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008671 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00008672 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008673 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008674}
8675
8676
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008677RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008678 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008679 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008680
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008681 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008682}
8683
8684
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008685RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008686 NoHandleAllocation ha;
8687 ASSERT(args.length() == 1);
8688
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008689 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008690 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008691}
8692
8693
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008694RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008695 ASSERT(args.length() == 1);
8696 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008697 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008698 return JSGlobalObject::cast(global)->global_receiver();
8699}
8700
8701
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008702RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008703 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008704 ASSERT_EQ(1, args.length());
8705 CONVERT_ARG_CHECKED(String, source, 0);
8706
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00008707 source = Handle<String>(source->TryFlattenGetString());
8708 // Optimized fast case where we only have ascii characters.
8709 Handle<Object> result;
8710 if (source->IsSeqAsciiString()) {
8711 result = JsonParser<true>::Parse(source);
8712 } else {
8713 result = JsonParser<false>::Parse(source);
8714 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008715 if (result.is_null()) {
8716 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008717 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008718 return Failure::Exception();
8719 }
8720 return *result;
8721}
8722
8723
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008724bool CodeGenerationFromStringsAllowed(Isolate* isolate,
8725 Handle<Context> context) {
8726 if (context->allow_code_gen_from_strings()->IsFalse()) {
8727 // Check with callback if set.
8728 AllowCodeGenerationFromStringsCallback callback =
8729 isolate->allow_code_gen_callback();
8730 if (callback == NULL) {
8731 // No callback set and code generation disallowed.
8732 return false;
8733 } else {
8734 // Callback set. Let it decide if code generation is allowed.
8735 VMState state(isolate, EXTERNAL);
8736 return callback(v8::Utils::ToLocal(context));
8737 }
8738 }
8739 return true;
8740}
8741
8742
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008743RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008744 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008745 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008746 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008747
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008748 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008749 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008750
8751 // Check if global context allows code generation from
8752 // strings. Throw an exception if it doesn't.
8753 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
8754 return isolate->Throw(*isolate->factory()->NewError(
8755 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8756 }
8757
8758 // Compile source string in the global context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008759 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
8760 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008761 true,
8762 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008763 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008764 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008765 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8766 context,
8767 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008768 return *fun;
8769}
8770
8771
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008772static ObjectPair CompileGlobalEval(Isolate* isolate,
8773 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008774 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008775 StrictModeFlag strict_mode) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008776 Handle<Context> context = Handle<Context>(isolate->context());
8777 Handle<Context> global_context = Handle<Context>(context->global_context());
8778
8779 // Check if global context allows code generation from
8780 // strings. Throw an exception if it doesn't.
8781 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
8782 isolate->Throw(*isolate->factory()->NewError(
8783 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8784 return MakePair(Failure::Exception(), NULL);
8785 }
8786
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008787 // Deal with a normal eval call with a string argument. Compile it
8788 // and return the compiled function bound in the local context.
8789 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
8790 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008791 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008792 context->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008793 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008794 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008795 Handle<JSFunction> compiled =
8796 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008797 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008798 return MakePair(*compiled, *receiver);
8799}
8800
8801
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008802RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008803 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008804
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008805 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008806 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008807 Handle<Object> receiver; // Will be overwritten.
8808
8809 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008810 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008811#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008812 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008813 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008814 StackFrameLocator locator;
8815 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008816 ASSERT(Context::cast(frame->context()) == *context);
8817#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008818
8819 // Find where the 'eval' symbol is bound. It is unaliased only if
8820 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008821 int index = -1;
8822 PropertyAttributes attributes = ABSENT;
8823 while (true) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008824 receiver = context->Lookup(isolate->factory()->eval_symbol(),
8825 FOLLOW_PROTOTYPE_CHAIN,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008826 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008827 // Stop search when eval is found or when the global context is
8828 // reached.
8829 if (attributes != ABSENT || context->IsGlobalContext()) break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008830 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008831 }
8832
iposva@chromium.org245aa852009-02-10 00:49:54 +00008833 // If eval could not be resolved, it has been deleted and we need to
8834 // throw a reference error.
8835 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008836 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00008837 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008838 isolate->factory()->NewReferenceError("not_defined",
8839 HandleVector(&name, 1));
8840 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008841 }
8842
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008843 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008844 // 'eval' is not bound in the global context. Just call the function
8845 // with the given arguments. This is not necessarily the global eval.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00008846 if (receiver->IsContext() || receiver->IsJSContextExtensionObject()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008847 receiver = isolate->factory()->the_hole_value();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008848 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008849 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008850 }
8851
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008852 // 'eval' is bound in the global context, but it may have been overwritten.
8853 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008854 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008855 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008856 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008857 }
8858
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008859 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008860 return CompileGlobalEval(isolate,
8861 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008862 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008863 static_cast<StrictModeFlag>(args.smi_at(3)));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008864}
8865
8866
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008867RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008868 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008869
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008870 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008871 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008872
8873 // 'eval' is bound in the global context, but it may have been overwritten.
8874 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008875 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008876 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008877 return MakePair(*callee, isolate->heap()->the_hole_value());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008878 }
8879
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008880 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008881 return CompileGlobalEval(isolate,
8882 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008883 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008884 static_cast<StrictModeFlag>(args.smi_at(3)));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008885}
8886
8887
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008888RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008889 // This utility adjusts the property attributes for newly created Function
8890 // object ("new Function(...)") by changing the map.
8891 // All it does is changing the prototype property to enumerable
8892 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008893 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008894 ASSERT(args.length() == 1);
8895 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008896
8897 Handle<Map> map = func->shared()->strict_mode()
8898 ? isolate->strict_mode_function_instance_map()
8899 : isolate->function_instance_map();
8900
8901 ASSERT(func->map()->instance_type() == map->instance_type());
8902 ASSERT(func->map()->instance_size() == map->instance_size());
8903 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008904 return *func;
8905}
8906
8907
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008908RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008909 // Allocate a block of memory in NewSpace (filled with a filler).
8910 // Use as fallback for allocation in generated code when NewSpace
8911 // is full.
8912 ASSERT(args.length() == 1);
8913 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
8914 int size = size_smi->value();
8915 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
8916 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008917 Heap* heap = isolate->heap();
8918 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008919 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008920 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008921 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008922 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008923 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008924 }
8925 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008926 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008927}
8928
8929
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008930// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008931// array. Returns true if the element was pushed on the stack and
8932// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008933RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008934 ASSERT(args.length() == 2);
8935 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008936 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008937 RUNTIME_ASSERT(array->HasFastElements());
8938 int length = Smi::cast(array->length())->value();
8939 FixedArray* elements = FixedArray::cast(array->elements());
8940 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008941 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008942 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008943 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008944 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008945 { MaybeObject* maybe_obj =
8946 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008947 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8948 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008949 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008950}
8951
8952
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008953/**
8954 * A simple visitor visits every element of Array's.
8955 * The backend storage can be a fixed array for fast elements case,
8956 * or a dictionary for sparse array. Since Dictionary is a subtype
8957 * of FixedArray, the class can be used by both fast and slow cases.
8958 * The second parameter of the constructor, fast_elements, specifies
8959 * whether the storage is a FixedArray or Dictionary.
8960 *
8961 * An index limit is used to deal with the situation that a result array
8962 * length overflows 32-bit non-negative integer.
8963 */
8964class ArrayConcatVisitor {
8965 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008966 ArrayConcatVisitor(Isolate* isolate,
8967 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008968 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008969 isolate_(isolate),
8970 storage_(Handle<FixedArray>::cast(
8971 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008972 index_offset_(0u),
8973 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008974
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008975 ~ArrayConcatVisitor() {
8976 clear_storage();
8977 }
8978
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008979 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008980 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008981 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008982
8983 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008984 if (index < static_cast<uint32_t>(storage_->length())) {
8985 storage_->set(index, *elm);
8986 return;
8987 }
8988 // Our initial estimate of length was foiled, possibly by
8989 // getters on the arrays increasing the length of later arrays
8990 // during iteration.
8991 // This shouldn't happen in anything but pathological cases.
8992 SetDictionaryMode(index);
8993 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008994 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008995 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008996 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008997 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008998 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008999 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009000 // Dictionary needed to grow.
9001 clear_storage();
9002 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009003 }
9004}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009005
9006 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009007 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9008 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009009 } else {
9010 index_offset_ += delta;
9011 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009012 }
9013
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009014 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009015 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009016 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009017 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009018 Handle<Map> map;
9019 if (fast_elements_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009020 map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009021 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009022 map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009023 }
9024 array->set_map(*map);
9025 array->set_length(*length);
9026 array->set_elements(*storage_);
9027 return array;
9028 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009029
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009030 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009031 // Convert storage to dictionary mode.
9032 void SetDictionaryMode(uint32_t index) {
9033 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009034 Handle<FixedArray> current_storage(*storage_);
9035 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009036 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009037 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9038 for (uint32_t i = 0; i < current_length; i++) {
9039 HandleScope loop_scope;
9040 Handle<Object> element(current_storage->get(i));
9041 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009042 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009043 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009044 if (!new_storage.is_identical_to(slow_storage)) {
9045 slow_storage = loop_scope.CloseAndEscape(new_storage);
9046 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009047 }
9048 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009049 clear_storage();
9050 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009051 fast_elements_ = false;
9052 }
9053
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009054 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009055 isolate_->global_handles()->Destroy(
9056 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009057 }
9058
9059 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009060 storage_ = Handle<FixedArray>::cast(
9061 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009062 }
9063
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009064 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009065 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009066 // Index after last seen index. Always less than or equal to
9067 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009068 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009069 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009070};
9071
9072
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009073static uint32_t EstimateElementCount(Handle<JSArray> array) {
9074 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9075 int element_count = 0;
9076 switch (array->GetElementsKind()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009077 case JSObject::FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009078 // Fast elements can't have lengths that are not representable by
9079 // a 32-bit signed integer.
9080 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9081 int fast_length = static_cast<int>(length);
9082 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9083 for (int i = 0; i < fast_length; i++) {
9084 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009085 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009086 break;
9087 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009088 case JSObject::DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009089 Handle<NumberDictionary> dictionary(
9090 NumberDictionary::cast(array->elements()));
9091 int capacity = dictionary->Capacity();
9092 for (int i = 0; i < capacity; i++) {
9093 Handle<Object> key(dictionary->KeyAt(i));
9094 if (dictionary->IsKey(*key)) {
9095 element_count++;
9096 }
9097 }
9098 break;
9099 }
9100 default:
9101 // External arrays are always dense.
9102 return length;
9103 }
9104 // As an estimate, we assume that the prototype doesn't contain any
9105 // inherited elements.
9106 return element_count;
9107}
9108
9109
9110
9111template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009112static void IterateExternalArrayElements(Isolate* isolate,
9113 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009114 bool elements_are_ints,
9115 bool elements_are_guaranteed_smis,
9116 ArrayConcatVisitor* visitor) {
9117 Handle<ExternalArrayClass> array(
9118 ExternalArrayClass::cast(receiver->elements()));
9119 uint32_t len = static_cast<uint32_t>(array->length());
9120
9121 ASSERT(visitor != NULL);
9122 if (elements_are_ints) {
9123 if (elements_are_guaranteed_smis) {
9124 for (uint32_t j = 0; j < len; j++) {
9125 HandleScope loop_scope;
9126 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
9127 visitor->visit(j, e);
9128 }
9129 } else {
9130 for (uint32_t j = 0; j < len; j++) {
9131 HandleScope loop_scope;
9132 int64_t val = static_cast<int64_t>(array->get(j));
9133 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9134 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9135 visitor->visit(j, e);
9136 } else {
9137 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009138 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009139 visitor->visit(j, e);
9140 }
9141 }
9142 }
9143 } else {
9144 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009145 HandleScope loop_scope(isolate);
9146 Handle<Object> e = isolate->factory()->NewNumber(array->get(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009147 visitor->visit(j, e);
9148 }
9149 }
9150}
9151
9152
9153// Used for sorting indices in a List<uint32_t>.
9154static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9155 uint32_t a = *ap;
9156 uint32_t b = *bp;
9157 return (a == b) ? 0 : (a < b) ? -1 : 1;
9158}
9159
9160
9161static void CollectElementIndices(Handle<JSObject> object,
9162 uint32_t range,
9163 List<uint32_t>* indices) {
9164 JSObject::ElementsKind kind = object->GetElementsKind();
9165 switch (kind) {
9166 case JSObject::FAST_ELEMENTS: {
9167 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9168 uint32_t length = static_cast<uint32_t>(elements->length());
9169 if (range < length) length = range;
9170 for (uint32_t i = 0; i < length; i++) {
9171 if (!elements->get(i)->IsTheHole()) {
9172 indices->Add(i);
9173 }
9174 }
9175 break;
9176 }
9177 case JSObject::DICTIONARY_ELEMENTS: {
9178 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009179 uint32_t capacity = dict->Capacity();
9180 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009181 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009182 Handle<Object> k(dict->KeyAt(j));
9183 if (dict->IsKey(*k)) {
9184 ASSERT(k->IsNumber());
9185 uint32_t index = static_cast<uint32_t>(k->Number());
9186 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009187 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009188 }
9189 }
9190 }
9191 break;
9192 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009193 default: {
9194 int dense_elements_length;
9195 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009196 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009197 dense_elements_length =
9198 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009199 break;
9200 }
9201 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009202 dense_elements_length =
9203 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009204 break;
9205 }
9206 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009207 dense_elements_length =
9208 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009209 break;
9210 }
9211 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009212 dense_elements_length =
9213 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009214 break;
9215 }
9216 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009217 dense_elements_length =
9218 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009219 break;
9220 }
9221 case JSObject::EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009222 dense_elements_length =
9223 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009224 break;
9225 }
9226 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009227 dense_elements_length =
9228 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009229 break;
9230 }
9231 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009232 dense_elements_length =
9233 ExternalFloatArray::cast(object->elements())->length();
9234 break;
9235 }
9236 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9237 dense_elements_length =
9238 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009239 break;
9240 }
9241 default:
9242 UNREACHABLE();
9243 dense_elements_length = 0;
9244 break;
9245 }
9246 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9247 if (range <= length) {
9248 length = range;
9249 // We will add all indices, so we might as well clear it first
9250 // and avoid duplicates.
9251 indices->Clear();
9252 }
9253 for (uint32_t i = 0; i < length; i++) {
9254 indices->Add(i);
9255 }
9256 if (length == range) return; // All indices accounted for already.
9257 break;
9258 }
9259 }
9260
9261 Handle<Object> prototype(object->GetPrototype());
9262 if (prototype->IsJSObject()) {
9263 // The prototype will usually have no inherited element indices,
9264 // but we have to check.
9265 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9266 }
9267}
9268
9269
9270/**
9271 * A helper function that visits elements of a JSArray in numerical
9272 * order.
9273 *
9274 * The visitor argument called for each existing element in the array
9275 * with the element index and the element's value.
9276 * Afterwards it increments the base-index of the visitor by the array
9277 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009278 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009279 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009280static bool IterateElements(Isolate* isolate,
9281 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009282 ArrayConcatVisitor* visitor) {
9283 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9284 switch (receiver->GetElementsKind()) {
9285 case JSObject::FAST_ELEMENTS: {
9286 // Run through the elements FixedArray and use HasElement and GetElement
9287 // to check the prototype for missing elements.
9288 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9289 int fast_length = static_cast<int>(length);
9290 ASSERT(fast_length <= elements->length());
9291 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009292 HandleScope loop_scope(isolate);
9293 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009294 if (!element_value->IsTheHole()) {
9295 visitor->visit(j, element_value);
9296 } else if (receiver->HasElement(j)) {
9297 // Call GetElement on receiver, not its prototype, or getters won't
9298 // have the correct receiver.
9299 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009300 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009301 visitor->visit(j, element_value);
9302 }
9303 }
9304 break;
9305 }
9306 case JSObject::DICTIONARY_ELEMENTS: {
9307 Handle<NumberDictionary> dict(receiver->element_dictionary());
9308 List<uint32_t> indices(dict->Capacity() / 2);
9309 // Collect all indices in the object and the prototypes less
9310 // than length. This might introduce duplicates in the indices list.
9311 CollectElementIndices(receiver, length, &indices);
9312 indices.Sort(&compareUInt32);
9313 int j = 0;
9314 int n = indices.length();
9315 while (j < n) {
9316 HandleScope loop_scope;
9317 uint32_t index = indices[j];
9318 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009319 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009320 visitor->visit(index, element);
9321 // Skip to next different index (i.e., omit duplicates).
9322 do {
9323 j++;
9324 } while (j < n && indices[j] == index);
9325 }
9326 break;
9327 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009328 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
9329 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9330 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009331 for (uint32_t j = 0; j < length; j++) {
9332 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
9333 visitor->visit(j, e);
9334 }
9335 break;
9336 }
9337 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
9338 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009339 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009340 break;
9341 }
9342 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
9343 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009344 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009345 break;
9346 }
9347 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
9348 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009349 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009350 break;
9351 }
9352 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
9353 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009354 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009355 break;
9356 }
9357 case JSObject::EXTERNAL_INT_ELEMENTS: {
9358 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009359 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009360 break;
9361 }
9362 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
9363 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009364 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009365 break;
9366 }
9367 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
9368 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009369 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009370 break;
9371 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009372 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9373 IterateExternalArrayElements<ExternalDoubleArray, double>(
9374 isolate, receiver, false, false, visitor);
9375 break;
9376 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009377 default:
9378 UNREACHABLE();
9379 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009380 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009381 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009382 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009383}
9384
9385
9386/**
9387 * Array::concat implementation.
9388 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009389 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009390 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009391 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009392RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009393 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009394 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009395
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009396 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
9397 int argument_count = static_cast<int>(arguments->length()->Number());
9398 RUNTIME_ASSERT(arguments->HasFastElements());
9399 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009400
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009401 // Pass 1: estimate the length and number of elements of the result.
9402 // The actual length can be larger if any of the arguments have getters
9403 // that mutate other arguments (but will otherwise be precise).
9404 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009405
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009406 uint32_t estimate_result_length = 0;
9407 uint32_t estimate_nof_elements = 0;
9408 {
9409 for (int i = 0; i < argument_count; i++) {
9410 HandleScope loop_scope;
9411 Handle<Object> obj(elements->get(i));
9412 uint32_t length_estimate;
9413 uint32_t element_estimate;
9414 if (obj->IsJSArray()) {
9415 Handle<JSArray> array(Handle<JSArray>::cast(obj));
9416 length_estimate =
9417 static_cast<uint32_t>(array->length()->Number());
9418 element_estimate =
9419 EstimateElementCount(array);
9420 } else {
9421 length_estimate = 1;
9422 element_estimate = 1;
9423 }
9424 // Avoid overflows by capping at kMaxElementCount.
9425 if (JSObject::kMaxElementCount - estimate_result_length <
9426 length_estimate) {
9427 estimate_result_length = JSObject::kMaxElementCount;
9428 } else {
9429 estimate_result_length += length_estimate;
9430 }
9431 if (JSObject::kMaxElementCount - estimate_nof_elements <
9432 element_estimate) {
9433 estimate_nof_elements = JSObject::kMaxElementCount;
9434 } else {
9435 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009436 }
9437 }
9438 }
9439
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009440 // If estimated number of elements is more than half of length, a
9441 // fixed array (fast case) is more time and space-efficient than a
9442 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009443 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009444
9445 Handle<FixedArray> storage;
9446 if (fast_case) {
9447 // The backing storage array must have non-existing elements to
9448 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009449 storage = isolate->factory()->NewFixedArrayWithHoles(
9450 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009451 } else {
9452 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9453 uint32_t at_least_space_for = estimate_nof_elements +
9454 (estimate_nof_elements >> 2);
9455 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009456 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009457 }
9458
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009459 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009460
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009461 for (int i = 0; i < argument_count; i++) {
9462 Handle<Object> obj(elements->get(i));
9463 if (obj->IsJSArray()) {
9464 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009465 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009466 return Failure::Exception();
9467 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009468 } else {
9469 visitor.visit(0, obj);
9470 visitor.increase_index_offset(1);
9471 }
9472 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009473
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009474 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009475}
9476
9477
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009478// This will not allocate (flatten the string), but it may run
9479// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009480RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009481 NoHandleAllocation ha;
9482 ASSERT(args.length() == 1);
9483
9484 CONVERT_CHECKED(String, string, args[0]);
9485 StringInputBuffer buffer(string);
9486 while (buffer.has_more()) {
9487 uint16_t character = buffer.GetNext();
9488 PrintF("%c", character);
9489 }
9490 return string;
9491}
9492
ager@chromium.org5ec48922009-05-05 07:25:34 +00009493// Moves all own elements of an object, that are below a limit, to positions
9494// starting at zero. All undefined values are placed after non-undefined values,
9495// and are followed by non-existing element. Does not change the length
9496// property.
9497// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009498RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009499 ASSERT(args.length() == 2);
9500 CONVERT_CHECKED(JSObject, object, args[0]);
9501 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9502 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009503}
9504
9505
9506// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009507RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009508 ASSERT(args.length() == 2);
9509 CONVERT_CHECKED(JSArray, from, args[0]);
9510 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009511 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009512 MaybeObject* maybe_new_map;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009513 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9514 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009515 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009516 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009517 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009518 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009519 Object* new_map;
9520 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009521 to->set_map(Map::cast(new_map));
9522 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009523 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009524 Object* obj;
9525 { MaybeObject* maybe_obj = from->ResetElements();
9526 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9527 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009528 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009529 return to;
9530}
9531
9532
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009533// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009534RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009535 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009536 CONVERT_CHECKED(JSObject, object, args[0]);
9537 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009538 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009539 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009540 } else if (object->IsJSArray()) {
9541 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009542 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009543 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009544 }
9545}
9546
9547
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009548RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009549 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009550
9551 ASSERT_EQ(3, args.length());
9552
ager@chromium.orgac091b72010-05-05 07:34:42 +00009553 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009554 Handle<Object> key1 = args.at<Object>(1);
9555 Handle<Object> key2 = args.at<Object>(2);
9556
9557 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009558 if (!key1->ToArrayIndex(&index1)
9559 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009560 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009561 }
9562
ager@chromium.orgac091b72010-05-05 07:34:42 +00009563 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
9564 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009565 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009566 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009567 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009568
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009569 RETURN_IF_EMPTY_HANDLE(isolate,
9570 SetElement(jsobject, index1, tmp2, kStrictMode));
9571 RETURN_IF_EMPTY_HANDLE(isolate,
9572 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00009573
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009574 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009575}
9576
9577
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009578// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009579// might have elements. Can either return keys (positive integers) or
9580// intervals (pair of a negative integer (-start-1) followed by a
9581// positive (length)) or undefined values.
9582// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009583RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009584 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009585 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009586 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009587 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009588 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009589 // Create an array and get all the keys into it, then remove all the
9590 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009591 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009592 int keys_length = keys->length();
9593 for (int i = 0; i < keys_length; i++) {
9594 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009595 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009596 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009597 // Zap invalid keys.
9598 keys->set_undefined(i);
9599 }
9600 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009601 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009602 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009603 ASSERT(array->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009604 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009605 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009606 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009607 uint32_t actual_length =
9608 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009609 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009610 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009611 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009612 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009613 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009614 }
9615}
9616
9617
9618// DefineAccessor takes an optional final argument which is the
9619// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
9620// to the way accessors are implemented, it is set for both the getter
9621// and setter on the first call to DefineAccessor and ignored on
9622// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009623RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009624 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
9625 // Compute attributes.
9626 PropertyAttributes attributes = NONE;
9627 if (args.length() == 5) {
9628 CONVERT_CHECKED(Smi, attrs, args[4]);
9629 int value = attrs->value();
9630 // Only attribute bits should be set.
9631 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
9632 attributes = static_cast<PropertyAttributes>(value);
9633 }
9634
9635 CONVERT_CHECKED(JSObject, obj, args[0]);
9636 CONVERT_CHECKED(String, name, args[1]);
9637 CONVERT_CHECKED(Smi, flag, args[2]);
9638 CONVERT_CHECKED(JSFunction, fun, args[3]);
9639 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
9640}
9641
9642
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009643RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009644 ASSERT(args.length() == 3);
9645 CONVERT_CHECKED(JSObject, obj, args[0]);
9646 CONVERT_CHECKED(String, name, args[1]);
9647 CONVERT_CHECKED(Smi, flag, args[2]);
9648 return obj->LookupAccessor(name, flag->value() == 0);
9649}
9650
9651
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009652#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009653RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009654 ASSERT(args.length() == 0);
9655 return Execution::DebugBreakHelper();
9656}
9657
9658
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009659// Helper functions for wrapping and unwrapping stack frame ids.
9660static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009661 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009662 return Smi::FromInt(id >> 2);
9663}
9664
9665
9666static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
9667 return static_cast<StackFrame::Id>(wrapped->value() << 2);
9668}
9669
9670
9671// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00009672// args[0]: debug event listener function to set or null or undefined for
9673// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009674// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009675RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009676 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009677 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
9678 args[0]->IsUndefined() ||
9679 args[0]->IsNull());
9680 Handle<Object> callback = args.at<Object>(0);
9681 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009682 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009683
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009684 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009685}
9686
9687
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009688RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +00009689 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009690 isolate->stack_guard()->DebugBreak();
9691 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009692}
9693
9694
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009695static MaybeObject* DebugLookupResultValue(Heap* heap,
9696 Object* receiver,
9697 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009698 LookupResult* result,
9699 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009700 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009701 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009702 case NORMAL:
9703 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009704 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009705 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009706 }
9707 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009708 case FIELD:
9709 value =
9710 JSObject::cast(
9711 result->holder())->FastPropertyAt(result->GetFieldIndex());
9712 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009713 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009714 }
9715 return value;
9716 case CONSTANT_FUNCTION:
9717 return result->GetConstantFunction();
9718 case CALLBACKS: {
9719 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00009720 if (structure->IsForeign() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009721 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009722 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009723 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009724 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009725 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009726 maybe_value = heap->isolate()->pending_exception();
9727 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009728 if (caught_exception != NULL) {
9729 *caught_exception = true;
9730 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009731 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009732 }
9733 return value;
9734 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009735 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009736 }
9737 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009738 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009739 case MAP_TRANSITION:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009740 case EXTERNAL_ARRAY_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009741 case CONSTANT_TRANSITION:
9742 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009743 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009744 default:
9745 UNREACHABLE();
9746 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009747 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009748 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009749}
9750
9751
ager@chromium.org32912102009-01-16 10:38:43 +00009752// Get debugger related details for an object property.
9753// args[0]: object holding property
9754// args[1]: name of the property
9755//
9756// The array returned contains the following information:
9757// 0: Property value
9758// 1: Property details
9759// 2: Property value is exception
9760// 3: Getter function if defined
9761// 4: Setter function if defined
9762// Items 2-4 are only filled if the property has either a getter or a setter
9763// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009764RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009765 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009766
9767 ASSERT(args.length() == 2);
9768
9769 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9770 CONVERT_ARG_CHECKED(String, name, 1);
9771
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009772 // Make sure to set the current context to the context before the debugger was
9773 // entered (if the debugger is entered). The reason for switching context here
9774 // is that for some property lookups (accessors and interceptors) callbacks
9775 // into the embedding application can occour, and the embedding application
9776 // could have the assumption that its own global context is the current
9777 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009778 SaveContext save(isolate);
9779 if (isolate->debug()->InDebugger()) {
9780 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009781 }
9782
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009783 // Skip the global proxy as it has no properties and always delegates to the
9784 // real global object.
9785 if (obj->IsJSGlobalProxy()) {
9786 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
9787 }
9788
9789
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009790 // Check if the name is trivially convertible to an index and get the element
9791 // if so.
9792 uint32_t index;
9793 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009794 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009795 Object* element_or_char;
9796 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009797 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009798 if (!maybe_element_or_char->ToObject(&element_or_char)) {
9799 return maybe_element_or_char;
9800 }
9801 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009802 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009803 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009804 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009805 }
9806
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009807 // Find the number of objects making up this.
9808 int length = LocalPrototypeChainLength(*obj);
9809
9810 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009811 Handle<JSObject> jsproto = obj;
9812 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009813 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009814 jsproto->LocalLookup(*name, &result);
9815 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009816 // LookupResult is not GC safe as it holds raw object pointers.
9817 // GC can happen later in this code so put the required fields into
9818 // local variables using handles when required for later use.
9819 PropertyType result_type = result.type();
9820 Handle<Object> result_callback_obj;
9821 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009822 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
9823 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009824 }
9825 Smi* property_details = result.GetPropertyDetails().AsSmi();
9826 // DebugLookupResultValue can cause GC so details from LookupResult needs
9827 // to be copied to handles before this.
9828 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009829 Object* raw_value;
9830 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009831 DebugLookupResultValue(isolate->heap(), *obj, *name,
9832 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009833 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
9834 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009835 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009836
9837 // If the callback object is a fixed array then it contains JavaScript
9838 // getter and/or setter.
9839 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
9840 result_callback_obj->IsFixedArray();
9841 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009842 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009843 details->set(0, *value);
9844 details->set(1, property_details);
9845 if (hasJavaScriptAccessors) {
9846 details->set(2,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009847 caught_exception ? isolate->heap()->true_value()
9848 : isolate->heap()->false_value());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009849 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
9850 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
9851 }
9852
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009853 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009854 }
9855 if (i < length - 1) {
9856 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
9857 }
9858 }
9859
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009860 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009861}
9862
9863
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009864RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009865 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009866
9867 ASSERT(args.length() == 2);
9868
9869 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9870 CONVERT_ARG_CHECKED(String, name, 1);
9871
9872 LookupResult result;
9873 obj->Lookup(*name, &result);
9874 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009875 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009876 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009877 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009878}
9879
9880
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009881// Return the property type calculated from the property details.
9882// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009883RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009884 ASSERT(args.length() == 1);
9885 CONVERT_CHECKED(Smi, details, args[0]);
9886 PropertyType type = PropertyDetails(details).type();
9887 return Smi::FromInt(static_cast<int>(type));
9888}
9889
9890
9891// Return the property attribute calculated from the property details.
9892// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009893RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009894 ASSERT(args.length() == 1);
9895 CONVERT_CHECKED(Smi, details, args[0]);
9896 PropertyAttributes attributes = PropertyDetails(details).attributes();
9897 return Smi::FromInt(static_cast<int>(attributes));
9898}
9899
9900
9901// Return the property insertion index calculated from the property details.
9902// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009903RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009904 ASSERT(args.length() == 1);
9905 CONVERT_CHECKED(Smi, details, args[0]);
9906 int index = PropertyDetails(details).index();
9907 return Smi::FromInt(index);
9908}
9909
9910
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009911// Return property value from named interceptor.
9912// args[0]: object
9913// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009914RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009915 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009916 ASSERT(args.length() == 2);
9917 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9918 RUNTIME_ASSERT(obj->HasNamedInterceptor());
9919 CONVERT_ARG_CHECKED(String, name, 1);
9920
9921 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009922 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009923}
9924
9925
9926// Return element value from indexed interceptor.
9927// args[0]: object
9928// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009929RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009930 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009931 ASSERT(args.length() == 2);
9932 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9933 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
9934 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
9935
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009936 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009937}
9938
9939
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009940RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009941 ASSERT(args.length() >= 1);
9942 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00009943 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009944 if (isolate->debug()->break_id() == 0 ||
9945 break_id != isolate->debug()->break_id()) {
9946 return isolate->Throw(
9947 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009948 }
9949
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009950 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009951}
9952
9953
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009954RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009955 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009956 ASSERT(args.length() == 1);
9957
9958 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009959 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009960 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
9961 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009962 if (!maybe_result->ToObject(&result)) return maybe_result;
9963 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009964
9965 // Count all frames which are relevant to debugging stack trace.
9966 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009967 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009968 if (id == StackFrame::NO_ID) {
9969 // If there is no JavaScript stack frame count is 0.
9970 return Smi::FromInt(0);
9971 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +00009972
9973 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
9974 n += it.frame()->GetInlineCount();
9975 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009976 return Smi::FromInt(n);
9977}
9978
9979
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00009980class FrameInspector {
9981 public:
9982 FrameInspector(JavaScriptFrame* frame,
9983 int inlined_frame_index,
9984 Isolate* isolate)
9985 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
9986 // Calculate the deoptimized frame.
9987 if (frame->is_optimized()) {
9988 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
9989 frame, inlined_frame_index, isolate);
9990 }
9991 has_adapted_arguments_ = frame_->has_adapted_arguments();
9992 is_optimized_ = frame_->is_optimized();
9993 }
9994
9995 ~FrameInspector() {
9996 // Get rid of the calculated deoptimized frame if any.
9997 if (deoptimized_frame_ != NULL) {
9998 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
9999 isolate_);
10000 }
10001 }
10002
10003 int GetParametersCount() {
10004 return is_optimized_
10005 ? deoptimized_frame_->parameters_count()
10006 : frame_->ComputeParametersCount();
10007 }
10008 int expression_count() { return deoptimized_frame_->expression_count(); }
10009 Object* GetFunction() {
10010 return is_optimized_
10011 ? deoptimized_frame_->GetFunction()
10012 : frame_->function();
10013 }
10014 Object* GetParameter(int index) {
10015 return is_optimized_
10016 ? deoptimized_frame_->GetParameter(index)
10017 : frame_->GetParameter(index);
10018 }
10019 Object* GetExpression(int index) {
10020 return is_optimized_
10021 ? deoptimized_frame_->GetExpression(index)
10022 : frame_->GetExpression(index);
10023 }
10024
10025 // To inspect all the provided arguments the frame might need to be
10026 // replaced with the arguments frame.
10027 void SetArgumentsFrame(JavaScriptFrame* frame) {
10028 ASSERT(has_adapted_arguments_);
10029 frame_ = frame;
10030 is_optimized_ = frame_->is_optimized();
10031 ASSERT(!is_optimized_);
10032 }
10033
10034 private:
10035 JavaScriptFrame* frame_;
10036 DeoptimizedFrameInfo* deoptimized_frame_;
10037 Isolate* isolate_;
10038 bool is_optimized_;
10039 bool has_adapted_arguments_;
10040
10041 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10042};
10043
10044
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010045static const int kFrameDetailsFrameIdIndex = 0;
10046static const int kFrameDetailsReceiverIndex = 1;
10047static const int kFrameDetailsFunctionIndex = 2;
10048static const int kFrameDetailsArgumentCountIndex = 3;
10049static const int kFrameDetailsLocalCountIndex = 4;
10050static const int kFrameDetailsSourcePositionIndex = 5;
10051static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010052static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010053static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010054static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010055
10056// Return an array with frame details
10057// args[0]: number: break id
10058// args[1]: number: frame index
10059//
10060// The array returned contains the following information:
10061// 0: Frame id
10062// 1: Receiver
10063// 2: Function
10064// 3: Argument count
10065// 4: Local count
10066// 5: Source position
10067// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010068// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010069// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010070// Arguments name, value
10071// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010072// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010073RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010074 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010075 ASSERT(args.length() == 2);
10076
10077 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010078 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010079 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10080 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010081 if (!maybe_check->ToObject(&check)) return maybe_check;
10082 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010083 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010084 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010085
10086 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010087 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010088 if (id == StackFrame::NO_ID) {
10089 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010090 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010091 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010092
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010093 int inlined_frame_index = 0; // Inlined frame index in optimized frame.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010094
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010095 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010096 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010097 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010098 if (index < count + it.frame()->GetInlineCount()) break;
10099 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010100 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010101 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010102
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010103 if (it.frame()->is_optimized()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010104 inlined_frame_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010105 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010106 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010107 FrameInspector frame_inspector(it.frame(), inlined_frame_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010108
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010109 // Traverse the saved contexts chain to find the active context for the
10110 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010111 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010112 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010113 save = save->prev();
10114 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010115 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010116
10117 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010118 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010119
10120 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010121 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010122 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010123
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010124 // Check for constructor frame. Inlined frames cannot be construct calls.
10125 bool inlined_frame =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010126 it.frame()->is_optimized() && inlined_frame_index != 0;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010127 bool constructor = !inlined_frame && it.frame()->IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010128
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010129 // Get scope info and read from it for local variable information.
10130 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000010131 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010132 ASSERT(*scope_info != SerializedScopeInfo::Empty());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010133 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010134
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010135 // Get the locals names and values into a temporary array.
10136 //
10137 // TODO(1240907): Hide compiler-introduced stack variables
10138 // (e.g. .result)? For users of the debugger, they will probably be
10139 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010140 Handle<FixedArray> locals =
10141 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010142
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010143 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010144 int i = 0;
10145 for (; i < info.number_of_stack_slots(); ++i) {
10146 // Use the value from the stack.
10147 locals->set(i * 2, *info.LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010148 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010149 }
10150 if (i < info.NumberOfLocals()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010151 // Get the context containing declarations.
10152 Handle<Context> context(
10153 Context::cast(it.frame()->context())->declaration_context());
10154 for (; i < info.NumberOfLocals(); ++i) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010155 Handle<String> name = info.LocalName(i);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010156 locals->set(i * 2, *name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010157 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010158 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010159 }
10160 }
10161
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010162 // Check whether this frame is positioned at return. If not top
10163 // frame or if the frame is optimized it cannot be at a return.
10164 bool at_return = false;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010165 if (!it.frame()->is_optimized() && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010166 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010167 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010168
10169 // If positioned just before return find the value to be returned and add it
10170 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010171 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010172 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010173 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010174 Address internal_frame_sp = NULL;
10175 while (!it2.done()) {
10176 if (it2.frame()->is_internal()) {
10177 internal_frame_sp = it2.frame()->sp();
10178 } else {
10179 if (it2.frame()->is_java_script()) {
10180 if (it2.frame()->id() == it.frame()->id()) {
10181 // The internal frame just before the JavaScript frame contains the
10182 // value to return on top. A debug break at return will create an
10183 // internal frame to store the return value (eax/rax/r0) before
10184 // entering the debug break exit frame.
10185 if (internal_frame_sp != NULL) {
10186 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010187 Handle<Object>(Memory::Object_at(internal_frame_sp),
10188 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010189 break;
10190 }
10191 }
10192 }
10193
10194 // Indicate that the previous frame was not an internal frame.
10195 internal_frame_sp = NULL;
10196 }
10197 it2.Advance();
10198 }
10199 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010200
10201 // Now advance to the arguments adapter frame (if any). It contains all
10202 // the provided parameters whereas the function frame always have the number
10203 // of arguments matching the functions parameters. The rest of the
10204 // information (except for what is collected above) is the same.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010205 if (it.frame()->has_adapted_arguments()) {
10206 it.AdvanceToArgumentsFrame();
10207 frame_inspector.SetArgumentsFrame(it.frame());
10208 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010209
10210 // Find the number of arguments to fill. At least fill the number of
10211 // parameters for the function and fill more if more parameters are provided.
10212 int argument_count = info.number_of_parameters();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010213 if (argument_count < frame_inspector.GetParametersCount()) {
10214 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010215 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010216#ifdef DEBUG
10217 if (it.frame()->is_optimized()) {
10218 ASSERT_EQ(argument_count, frame_inspector.GetParametersCount());
10219 }
10220#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010221
10222 // Calculate the size of the result.
10223 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010224 2 * (argument_count + info.NumberOfLocals()) +
10225 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010226 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010227
10228 // Add the frame id.
10229 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10230
10231 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010232 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010233
10234 // Add the arguments count.
10235 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10236
10237 // Add the locals count
10238 details->set(kFrameDetailsLocalCountIndex,
10239 Smi::FromInt(info.NumberOfLocals()));
10240
10241 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010242 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010243 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10244 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010245 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010246 }
10247
10248 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010249 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010250
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010251 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010252 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010253
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010254 // Add flags to indicate information on whether this frame is
10255 // bit 0: invoked in the debugger context.
10256 // bit 1: optimized frame.
10257 // bit 2: inlined in optimized frame
10258 int flags = 0;
10259 if (*save->context() == *isolate->debug()->debug_context()) {
10260 flags |= 1 << 0;
10261 }
10262 if (it.frame()->is_optimized()) {
10263 flags |= 1 << 1;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010264 flags |= inlined_frame_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010265 }
10266 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010267
10268 // Fill the dynamic part.
10269 int details_index = kFrameDetailsFirstDynamicIndex;
10270
10271 // Add arguments name and value.
10272 for (int i = 0; i < argument_count; i++) {
10273 // Name of the argument.
10274 if (i < info.number_of_parameters()) {
10275 details->set(details_index++, *info.parameter_name(i));
10276 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010277 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010278 }
10279
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010280 // Parameter value.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010281 if (i < it.frame()->ComputeParametersCount()) {
10282 // Get the value from the stack.
10283 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010284 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010285 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010286 }
10287 }
10288
10289 // Add locals name and value from the temporary copy from the function frame.
10290 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
10291 details->set(details_index++, locals->get(i));
10292 }
10293
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010294 // Add the value being returned.
10295 if (at_return) {
10296 details->set(details_index++, *return_value);
10297 }
10298
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010299 // Add the receiver (same as in function frame).
10300 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10301 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010302 Handle<Object> receiver(it.frame()->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010303 if (!receiver->IsJSObject()) {
10304 // If the receiver is NOT a JSObject we have hit an optimization
10305 // where a value object is not converted into a wrapped JS objects.
10306 // To hide this optimization from the debugger, we wrap the receiver
10307 // by creating correct wrapper object based on the calling frame's
10308 // global context.
10309 it.Advance();
10310 Handle<Context> calling_frames_global_context(
10311 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010312 receiver =
10313 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010314 }
10315 details->set(kFrameDetailsReceiverIndex, *receiver);
10316
10317 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010318 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010319}
10320
10321
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010322// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010323static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010324 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010325 Handle<SerializedScopeInfo> serialized_scope_info,
10326 ScopeInfo<>& scope_info,
10327 Handle<Context> context,
10328 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010329 // Fill all context locals to the context extension.
10330 for (int i = Context::MIN_CONTEXT_SLOTS;
10331 i < scope_info.number_of_context_slots();
10332 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +000010333 int context_index = serialized_scope_info->ContextSlotIndex(
10334 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010335
whesse@chromium.org7b260152011-06-20 15:33:18 +000010336 RETURN_IF_EMPTY_HANDLE_VALUE(
10337 isolate,
10338 SetProperty(scope_object,
10339 scope_info.context_slot_name(i),
10340 Handle<Object>(context->get(context_index), isolate),
10341 NONE,
10342 kNonStrictMode),
10343 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010344 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010345
10346 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010347}
10348
10349
10350// Create a plain JSObject which materializes the local scope for the specified
10351// frame.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010352static Handle<JSObject> MaterializeLocalScope(
10353 Isolate* isolate,
10354 JavaScriptFrame* frame,
10355 int inlined_frame_index) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010356 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010357 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010358 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10359 ScopeInfo<> scope_info(*serialized_scope_info);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010360 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010361
10362 // Allocate and initialize a JSObject with all the arguments, stack locals
10363 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010364 Handle<JSObject> local_scope =
10365 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010366
10367 // First fill all parameters.
10368 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010369 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010370 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010371 SetProperty(local_scope,
10372 scope_info.parameter_name(i),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010373 Handle<Object>(frame_inspector.GetParameter(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010374 NONE,
10375 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010376 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010377 }
10378
10379 // Second fill all stack locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010380 for (int i = 0; i < scope_info.number_of_stack_slots(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010381 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010382 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010383 SetProperty(local_scope,
10384 scope_info.stack_slot_name(i),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010385 Handle<Object>(frame_inspector.GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010386 NONE,
10387 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010388 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010389 }
10390
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010391 if (scope_info.number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
10392 // Third fill all context locals.
10393 Handle<Context> frame_context(Context::cast(frame->context()));
10394 Handle<Context> function_context(frame_context->declaration_context());
10395 if (!CopyContextLocalsToScopeObject(isolate,
10396 serialized_scope_info, scope_info,
10397 function_context, local_scope)) {
10398 return Handle<JSObject>();
10399 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010400
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010401 // Finally copy any properties from the function context extension.
10402 // These will be variables introduced by eval.
10403 if (function_context->closure() == *function) {
10404 if (function_context->has_extension() &&
10405 !function_context->IsGlobalContext()) {
10406 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
10407 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
10408 for (int i = 0; i < keys->length(); i++) {
10409 // Names of variables introduced by eval are strings.
10410 ASSERT(keys->get(i)->IsString());
10411 Handle<String> key(String::cast(keys->get(i)));
10412 RETURN_IF_EMPTY_HANDLE_VALUE(
10413 isolate,
10414 SetProperty(local_scope,
10415 key,
10416 GetProperty(ext, key),
10417 NONE,
10418 kNonStrictMode),
10419 Handle<JSObject>());
10420 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010421 }
10422 }
10423 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010424
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010425 return local_scope;
10426}
10427
10428
10429// Create a plain JSObject which materializes the closure content for the
10430// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010431static Handle<JSObject> MaterializeClosure(Isolate* isolate,
10432 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010433 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010434
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010435 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010436 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10437 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010438
10439 // Allocate and initialize a JSObject with all the content of theis function
10440 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010441 Handle<JSObject> closure_scope =
10442 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010443
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010444 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010445 if (!CopyContextLocalsToScopeObject(isolate,
10446 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010447 context, closure_scope)) {
10448 return Handle<JSObject>();
10449 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010450
10451 // Finally copy any properties from the function context extension. This will
10452 // be variables introduced by eval.
10453 if (context->has_extension()) {
10454 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010455 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010456 for (int i = 0; i < keys->length(); i++) {
10457 // Names of variables introduced by eval are strings.
10458 ASSERT(keys->get(i)->IsString());
10459 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010460 RETURN_IF_EMPTY_HANDLE_VALUE(
10461 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010462 SetProperty(closure_scope,
10463 key,
10464 GetProperty(ext, key),
10465 NONE,
10466 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010467 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010468 }
10469 }
10470
10471 return closure_scope;
10472}
10473
10474
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010475// Create a plain JSObject which materializes the scope for the specified
10476// catch context.
10477static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
10478 Handle<Context> context) {
10479 ASSERT(context->IsCatchContext());
10480 Handle<String> name(String::cast(context->extension()));
10481 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
10482 Handle<JSObject> catch_scope =
10483 isolate->factory()->NewJSObject(isolate->object_function());
10484 RETURN_IF_EMPTY_HANDLE_VALUE(
10485 isolate,
10486 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
10487 Handle<JSObject>());
10488 return catch_scope;
10489}
10490
10491
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010492// Iterate over the actual scopes visible from a stack frame. All scopes are
10493// backed by an actual context except the local scope, which is inserted
10494// "artifically" in the context chain.
10495class ScopeIterator {
10496 public:
10497 enum ScopeType {
10498 ScopeTypeGlobal = 0,
10499 ScopeTypeLocal,
10500 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010501 ScopeTypeClosure,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010502 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010503 };
10504
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010505 ScopeIterator(Isolate* isolate,
10506 JavaScriptFrame* frame,
10507 int inlined_frame_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010508 : isolate_(isolate),
10509 frame_(frame),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010510 inlined_frame_index_(inlined_frame_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010511 function_(JSFunction::cast(frame->function())),
10512 context_(Context::cast(frame->context())),
10513 local_done_(false),
10514 at_local_(false) {
10515
10516 // Check whether the first scope is actually a local scope.
10517 if (context_->IsGlobalContext()) {
10518 // If there is a stack slot for .result then this local scope has been
10519 // created for evaluating top level code and it is not a real local scope.
10520 // Checking for the existence of .result seems fragile, but the scope info
10521 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +000010522 int index = function_->shared()->scope_info()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010523 StackSlotIndex(isolate_->heap()->result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010524 at_local_ = index < 0;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010525 } else if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010526 at_local_ = true;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010527 } else if (context_->closure() != *function_) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010528 // The context_ is a with or catch block from the outer function.
10529 ASSERT(context_->IsWithContext() || context_->IsCatchContext());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010530 at_local_ = true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010531 }
10532 }
10533
10534 // More scopes?
10535 bool Done() { return context_.is_null(); }
10536
10537 // Move to the next scope.
10538 void Next() {
10539 // If at a local scope mark the local scope as passed.
10540 if (at_local_) {
10541 at_local_ = false;
10542 local_done_ = true;
10543
10544 // If the current context is not associated with the local scope the
10545 // current context is the next real scope, so don't move to the next
10546 // context in this case.
10547 if (context_->closure() != *function_) {
10548 return;
10549 }
10550 }
10551
10552 // The global scope is always the last in the chain.
10553 if (context_->IsGlobalContext()) {
10554 context_ = Handle<Context>();
10555 return;
10556 }
10557
10558 // Move to the next context.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010559 context_ = Handle<Context>(context_->previous(), isolate_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010560
10561 // If passing the local scope indicate that the current scope is now the
10562 // local scope.
10563 if (!local_done_ &&
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010564 (context_->IsGlobalContext() || context_->IsFunctionContext())) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010565 at_local_ = true;
10566 }
10567 }
10568
10569 // Return the type of the current scope.
10570 int Type() {
10571 if (at_local_) {
10572 return ScopeTypeLocal;
10573 }
10574 if (context_->IsGlobalContext()) {
10575 ASSERT(context_->global()->IsGlobalObject());
10576 return ScopeTypeGlobal;
10577 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010578 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010579 return ScopeTypeClosure;
10580 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010581 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010582 return ScopeTypeCatch;
10583 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010584 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010585 return ScopeTypeWith;
10586 }
10587
10588 // Return the JavaScript object with the content of the current scope.
10589 Handle<JSObject> ScopeObject() {
10590 switch (Type()) {
10591 case ScopeIterator::ScopeTypeGlobal:
10592 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010593 case ScopeIterator::ScopeTypeLocal:
10594 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010595 return MaterializeLocalScope(isolate_, frame_, inlined_frame_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010596 case ScopeIterator::ScopeTypeWith:
10597 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010598 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
10599 case ScopeIterator::ScopeTypeCatch:
10600 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010601 case ScopeIterator::ScopeTypeClosure:
10602 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010603 return MaterializeClosure(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010604 }
10605 UNREACHABLE();
10606 return Handle<JSObject>();
10607 }
10608
10609 // Return the context for this scope. For the local context there might not
10610 // be an actual context.
10611 Handle<Context> CurrentContext() {
10612 if (at_local_ && context_->closure() != *function_) {
10613 return Handle<Context>();
10614 }
10615 return context_;
10616 }
10617
10618#ifdef DEBUG
10619 // Debug print of the content of the current scope.
10620 void DebugPrint() {
10621 switch (Type()) {
10622 case ScopeIterator::ScopeTypeGlobal:
10623 PrintF("Global:\n");
10624 CurrentContext()->Print();
10625 break;
10626
10627 case ScopeIterator::ScopeTypeLocal: {
10628 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010629 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010630 scope_info.Print();
10631 if (!CurrentContext().is_null()) {
10632 CurrentContext()->Print();
10633 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010634 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010635 if (extension->IsJSContextExtensionObject()) {
10636 extension->Print();
10637 }
10638 }
10639 }
10640 break;
10641 }
10642
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010643 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010644 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010645 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010646 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010647
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010648 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000010649 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010650 CurrentContext()->extension()->Print();
10651 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000010652 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000010653
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010654 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010655 PrintF("Closure:\n");
10656 CurrentContext()->Print();
10657 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010658 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010659 if (extension->IsJSContextExtensionObject()) {
10660 extension->Print();
10661 }
10662 }
10663 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010664
10665 default:
10666 UNREACHABLE();
10667 }
10668 PrintF("\n");
10669 }
10670#endif
10671
10672 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010673 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010674 JavaScriptFrame* frame_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010675 int inlined_frame_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010676 Handle<JSFunction> function_;
10677 Handle<Context> context_;
10678 bool local_done_;
10679 bool at_local_;
10680
10681 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
10682};
10683
10684
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010685RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010686 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010687 ASSERT(args.length() == 2);
10688
10689 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010690 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010691 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10692 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010693 if (!maybe_check->ToObject(&check)) return maybe_check;
10694 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010695 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10696
10697 // Get the frame where the debugging is performed.
10698 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010699 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010700 JavaScriptFrame* frame = it.frame();
10701
10702 // Count the visible scopes.
10703 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010704 for (ScopeIterator it(isolate, frame, 0);
10705 !it.Done();
10706 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010707 n++;
10708 }
10709
10710 return Smi::FromInt(n);
10711}
10712
10713
10714static const int kScopeDetailsTypeIndex = 0;
10715static const int kScopeDetailsObjectIndex = 1;
10716static const int kScopeDetailsSize = 2;
10717
10718// Return an array with scope details
10719// args[0]: number: break id
10720// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010721// args[2]: number: inlined frame index
10722// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010723//
10724// The array returned contains the following information:
10725// 0: Scope type
10726// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010727RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010728 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010729 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010730
10731 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010732 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010733 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10734 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010735 if (!maybe_check->ToObject(&check)) return maybe_check;
10736 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010737 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010738 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
10739 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010740
10741 // Get the frame where the debugging is performed.
10742 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010743 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010744 JavaScriptFrame* frame = frame_it.frame();
10745
10746 // Find the requested scope.
10747 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010748 ScopeIterator it(isolate, frame, inlined_frame_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010749 for (; !it.Done() && n < index; it.Next()) {
10750 n++;
10751 }
10752 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010753 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010754 }
10755
10756 // Calculate the size of the result.
10757 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010758 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010759
10760 // Fill in scope details.
10761 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010762 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010763 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010764 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010765
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010766 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010767}
10768
10769
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010770RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010771 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010772 ASSERT(args.length() == 0);
10773
10774#ifdef DEBUG
10775 // Print the scopes for the top frame.
10776 StackFrameLocator locator;
10777 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010778 for (ScopeIterator it(isolate, frame, 0);
10779 !it.Done();
10780 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010781 it.DebugPrint();
10782 }
10783#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010784 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010785}
10786
10787
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010788RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010789 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010790 ASSERT(args.length() == 1);
10791
10792 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010793 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010794 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10795 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010796 if (!maybe_result->ToObject(&result)) return maybe_result;
10797 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010798
10799 // Count all archived V8 threads.
10800 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010801 for (ThreadState* thread =
10802 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010803 thread != NULL;
10804 thread = thread->Next()) {
10805 n++;
10806 }
10807
10808 // Total number of threads is current thread and archived threads.
10809 return Smi::FromInt(n + 1);
10810}
10811
10812
10813static const int kThreadDetailsCurrentThreadIndex = 0;
10814static const int kThreadDetailsThreadIdIndex = 1;
10815static const int kThreadDetailsSize = 2;
10816
10817// Return an array with thread details
10818// args[0]: number: break id
10819// args[1]: number: thread index
10820//
10821// The array returned contains the following information:
10822// 0: Is current thread?
10823// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010824RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010825 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010826 ASSERT(args.length() == 2);
10827
10828 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010829 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010830 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10831 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010832 if (!maybe_check->ToObject(&check)) return maybe_check;
10833 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010834 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
10835
10836 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010837 Handle<FixedArray> details =
10838 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010839
10840 // Thread index 0 is current thread.
10841 if (index == 0) {
10842 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010843 details->set(kThreadDetailsCurrentThreadIndex,
10844 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010845 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010846 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010847 } else {
10848 // Find the thread with the requested index.
10849 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010850 ThreadState* thread =
10851 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010852 while (index != n && thread != NULL) {
10853 thread = thread->Next();
10854 n++;
10855 }
10856 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010857 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010858 }
10859
10860 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010861 details->set(kThreadDetailsCurrentThreadIndex,
10862 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010863 details->set(kThreadDetailsThreadIdIndex,
10864 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010865 }
10866
10867 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010868 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010869}
10870
10871
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010872// Sets the disable break state
10873// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010874RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010875 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010876 ASSERT(args.length() == 1);
10877 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010878 isolate->debug()->set_disable_break(disable_break);
10879 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010880}
10881
10882
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010883RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010884 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010885 ASSERT(args.length() == 1);
10886
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010887 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10888 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010889 // Find the number of break points
10890 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010891 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010892 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010893 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010894 Handle<FixedArray>::cast(break_locations));
10895}
10896
10897
10898// Set a break point in a function
10899// args[0]: function
10900// args[1]: number: break source position (within the function source)
10901// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010902RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010903 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010904 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010905 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10906 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010907 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10908 RUNTIME_ASSERT(source_position >= 0);
10909 Handle<Object> break_point_object_arg = args.at<Object>(2);
10910
10911 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010912 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
10913 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010914
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010915 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010916}
10917
10918
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010919Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
10920 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010921 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010922 // Iterate the heap looking for SharedFunctionInfo generated from the
10923 // script. The inner most SharedFunctionInfo containing the source position
10924 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010925 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010926 // which is found is not compiled it is compiled and the heap is iterated
10927 // again as the compilation might create inner functions from the newly
10928 // compiled function and the actual requested break point might be in one of
10929 // these functions.
10930 bool done = false;
10931 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000010932 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010933 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010934 while (!done) {
10935 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010936 for (HeapObject* obj = iterator.next();
10937 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010938 if (obj->IsSharedFunctionInfo()) {
10939 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
10940 if (shared->script() == *script) {
10941 // If the SharedFunctionInfo found has the requested script data and
10942 // contains the source position it is a candidate.
10943 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +000010944 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010945 start_position = shared->start_position();
10946 }
10947 if (start_position <= position &&
10948 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +000010949 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010950 // candidate this is the new candidate.
10951 if (target.is_null()) {
10952 target_start_position = start_position;
10953 target = shared;
10954 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010955 if (target_start_position == start_position &&
10956 shared->end_position() == target->end_position()) {
10957 // If a top-level function contain only one function
10958 // declartion the source for the top-level and the function is
10959 // the same. In that case prefer the non top-level function.
10960 if (!shared->is_toplevel()) {
10961 target_start_position = start_position;
10962 target = shared;
10963 }
10964 } else if (target_start_position <= start_position &&
10965 shared->end_position() <= target->end_position()) {
10966 // This containment check includes equality as a function inside
10967 // a top-level function can share either start or end position
10968 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010969 target_start_position = start_position;
10970 target = shared;
10971 }
10972 }
10973 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010974 }
10975 }
10976 }
10977
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010978 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010979 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010980 }
10981
10982 // If the candidate found is compiled we are done. NOTE: when lazy
10983 // compilation of inner functions is introduced some additional checking
10984 // needs to be done here to compile inner functions.
10985 done = target->is_compiled();
10986 if (!done) {
10987 // If the candidate is not compiled compile it to reveal any inner
10988 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010989 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010990 }
10991 }
10992
10993 return *target;
10994}
10995
10996
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010997// Changes the state of a break point in a script and returns source position
10998// where break point was set. NOTE: Regarding performance see the NOTE for
10999// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011000// args[0]: script to set break point in
11001// args[1]: number: break source position (within the script source)
11002// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011003RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011004 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011005 ASSERT(args.length() == 3);
11006 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
11007 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11008 RUNTIME_ASSERT(source_position >= 0);
11009 Handle<Object> break_point_object_arg = args.at<Object>(2);
11010
11011 // Get the script from the script wrapper.
11012 RUNTIME_ASSERT(wrapper->value()->IsScript());
11013 Handle<Script> script(Script::cast(wrapper->value()));
11014
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011015 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011016 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011017 if (!result->IsUndefined()) {
11018 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11019 // Find position within function. The script position might be before the
11020 // source position of the first function.
11021 int position;
11022 if (shared->start_position() > source_position) {
11023 position = 0;
11024 } else {
11025 position = source_position - shared->start_position();
11026 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011027 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011028 position += shared->start_position();
11029 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011030 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011031 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011032}
11033
11034
11035// Clear a break point
11036// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011037RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011038 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011039 ASSERT(args.length() == 1);
11040 Handle<Object> break_point_object_arg = args.at<Object>(0);
11041
11042 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011043 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011044
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011045 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011046}
11047
11048
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011049// Change the state of break on exceptions.
11050// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11051// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011052RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011053 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011054 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011055 RUNTIME_ASSERT(args[0]->IsNumber());
11056 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011057
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011058 // If the number doesn't match an enum value, the ChangeBreakOnException
11059 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011060 ExceptionBreakType type =
11061 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011062 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011063 isolate->debug()->ChangeBreakOnException(type, enable);
11064 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011065}
11066
11067
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011068// Returns the state of break on exceptions
11069// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011070RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011071 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011072 ASSERT(args.length() == 1);
11073 RUNTIME_ASSERT(args[0]->IsNumber());
11074
11075 ExceptionBreakType type =
11076 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011077 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011078 return Smi::FromInt(result);
11079}
11080
11081
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011082// Prepare for stepping
11083// args[0]: break id for checking execution state
11084// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011085// args[2]: number of times to perform the step, for step out it is the number
11086// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011087RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011088 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011089 ASSERT(args.length() == 3);
11090 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011091 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011092 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11093 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011094 if (!maybe_check->ToObject(&check)) return maybe_check;
11095 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011096 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011097 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011098 }
11099
11100 // Get the step action and check validity.
11101 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11102 if (step_action != StepIn &&
11103 step_action != StepNext &&
11104 step_action != StepOut &&
11105 step_action != StepInMin &&
11106 step_action != StepMin) {
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 number of steps.
11111 int step_count = NumberToInt32(args[2]);
11112 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011113 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011114 }
11115
ager@chromium.orga1645e22009-09-09 19:27:10 +000011116 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011117 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011118
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011119 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011120 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11121 step_count);
11122 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011123}
11124
11125
11126// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011127RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011128 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011129 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011130 isolate->debug()->ClearStepping();
11131 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011132}
11133
11134
11135// Creates a copy of the with context chain. The copy of the context chain is
11136// is linked to the function context supplied.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011137static Handle<Context> CopyWithContextChain(Isolate* isolate,
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011138 Handle<JSFunction> function,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011139 Handle<Context> current,
11140 Handle<Context> base) {
11141 // At the end of the chain. Return the base context to link to.
11142 if (current->IsFunctionContext() || current->IsGlobalContext()) {
11143 return base;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011144 }
11145
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011146 // Recursively copy the with and catch contexts.
11147 HandleScope scope(isolate);
11148 Handle<Context> previous(current->previous());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011149 Handle<Context> new_previous =
11150 CopyWithContextChain(isolate, function, previous, base);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011151 Handle<Context> new_current;
11152 if (current->IsCatchContext()) {
11153 Handle<String> name(String::cast(current->extension()));
11154 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11155 new_current =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011156 isolate->factory()->NewCatchContext(function,
11157 new_previous,
11158 name,
11159 thrown_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011160 } else {
11161 Handle<JSObject> extension(JSObject::cast(current->extension()));
11162 new_current =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011163 isolate->factory()->NewWithContext(function, new_previous, extension);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011164 }
11165 return scope.CloseAndEscape(new_current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011166}
11167
11168
11169// Helper function to find or create the arguments object for
11170// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011171static Handle<Object> GetArgumentsObject(Isolate* isolate,
11172 JavaScriptFrame* frame,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011173 int inlined_frame_index,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011174 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000011175 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011176 const ScopeInfo<>* sinfo,
11177 Handle<Context> function_context) {
11178 // Try to find the value of 'arguments' to pass as parameter. If it is not
11179 // found (that is the debugged function does not reference 'arguments' and
11180 // does not support eval) then create an 'arguments' object.
11181 int index;
11182 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011183 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011184 if (index != -1) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011185 CHECK(false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011186 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011187 }
11188 }
11189
11190 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011191 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
11192 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011193 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011194 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011195 }
11196 }
11197
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011198 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
11199
11200 int length = frame_inspector.GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011201 Handle<JSObject> arguments =
11202 isolate->factory()->NewArgumentsObject(function, length);
11203 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011204
11205 AssertNoAllocation no_gc;
11206 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011207 for (int i = 0; i < length; i++) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011208 array->set(i, frame_inspector.GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011209 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011210 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011211 return arguments;
11212}
11213
11214
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011215static const char kSourceStr[] =
11216 "(function(arguments,__source__){return eval(__source__);})";
11217
11218
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011219// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000011220// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011221// extension part has all the parameters and locals of the function on the
11222// stack frame. A function which calls eval with the code to evaluate is then
11223// compiled in this context and called in this context. As this context
11224// replaces the context of the function on the stack frame a new (empty)
11225// function is created as well to be used as the closure for the context.
11226// This function and the context acts as replacements for the function on the
11227// stack frame presenting the same view of the values of parameters and
11228// local variables as if the piece of JavaScript was evaluated at the point
11229// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011230RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011231 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011232
11233 // Check the execution state and decode arguments frame and source to be
11234 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011235 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011236 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011237 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11238 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011239 if (!maybe_check_result->ToObject(&check_result)) {
11240 return maybe_check_result;
11241 }
11242 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011243 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011244 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
11245 CONVERT_ARG_CHECKED(String, source, 3);
11246 CONVERT_BOOLEAN_CHECKED(disable_break, args[4]);
11247 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011248
11249 // Handle the processing of break.
11250 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011251
11252 // Get the frame where the debugging is performed.
11253 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011254 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011255 JavaScriptFrame* frame = it.frame();
11256 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000011257 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011258 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011259
11260 // Traverse the saved contexts chain to find the active context for the
11261 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011262 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000011263 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011264 save = save->prev();
11265 }
11266 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011267 SaveContext savex(isolate);
11268 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011269
11270 // Create the (empty) function replacing the function on the stack frame for
11271 // the purpose of evaluating in the context created below. It is important
11272 // that this function does not describe any parameters and local variables
11273 // in the context. If it does then this will cause problems with the lookup
11274 // in Context::Lookup, where context slots for parameters and local variables
11275 // are looked at before the extension object.
11276 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011277 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
11278 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011279 go_between->set_context(function->context());
11280#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011281 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011282 ASSERT(go_between_sinfo.number_of_parameters() == 0);
11283 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
11284#endif
11285
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011286 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011287 Handle<JSObject> local_scope = MaterializeLocalScope(
11288 isolate, frame, inlined_frame_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011289 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011290
11291 // Allocate a new context for the debug evaluation and set the extension
11292 // object build.
11293 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011294 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11295 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011296 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011297 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011298 Handle<Context> frame_context(Context::cast(frame->context()));
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011299 Handle<Context> function_context(frame_context->declaration_context());
11300 context = CopyWithContextChain(isolate, go_between, frame_context, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011301
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011302 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011303 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011304 context =
11305 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011306 }
11307
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011308 // Wrap the evaluation statement in a new function compiled in the newly
11309 // created context. The function has one parameter which has to be called
11310 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000011311 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011312 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011313
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011314 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011315 isolate->factory()->NewStringFromAscii(
11316 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011317
11318 // Currently, the eval code will be executed in non-strict mode,
11319 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011320 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000011321 Compiler::CompileEval(function_source,
11322 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011323 context->IsGlobalContext(),
11324 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011325 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011326 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011327 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011328
11329 // Invoke the result of the compilation to get the evaluation function.
11330 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011331 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011332 Handle<Object> evaluation_function =
11333 Execution::Call(compiled_function, receiver, 0, NULL,
11334 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011335 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011336
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011337 Handle<Object> arguments = GetArgumentsObject(isolate,
11338 frame, inlined_frame_index,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011339 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011340 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011341
11342 // Invoke the evaluation function and return the result.
11343 const int argc = 2;
11344 Object** argv[argc] = { arguments.location(),
11345 Handle<Object>::cast(source).location() };
11346 Handle<Object> result =
11347 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
11348 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011349 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011350
11351 // Skip the global proxy as it has no properties and always delegates to the
11352 // real global object.
11353 if (result->IsJSGlobalProxy()) {
11354 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
11355 }
11356
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011357 return *result;
11358}
11359
11360
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011361RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011362 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011363
11364 // Check the execution state and decode arguments frame and source to be
11365 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011366 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011367 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011368 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11369 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011370 if (!maybe_check_result->ToObject(&check_result)) {
11371 return maybe_check_result;
11372 }
11373 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011374 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011375 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011376 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011377
11378 // Handle the processing of break.
11379 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011380
11381 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011382 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011383 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011384 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011385 top = top->prev();
11386 }
11387 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011388 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011389 }
11390
11391 // Get the global context now set to the top context from before the
11392 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011393 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011394
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011395 bool is_global = true;
11396
11397 if (additional_context->IsJSObject()) {
11398 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011399 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
11400 isolate->factory()->empty_string(),
11401 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011402 go_between->set_context(*context);
11403 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011404 isolate->factory()->NewFunctionContext(
11405 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011406 context->set_extension(JSObject::cast(*additional_context));
11407 is_global = false;
11408 }
11409
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011410 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011411 // Currently, the eval code will be executed in non-strict mode,
11412 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011413 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011414 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011415 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011416 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011417 Handle<JSFunction>(
11418 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
11419 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011420
11421 // Invoke the result of the compilation to get the evaluation function.
11422 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011423 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011424 Handle<Object> result =
11425 Execution::Call(compiled_function, receiver, 0, NULL,
11426 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011427 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011428 return *result;
11429}
11430
11431
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011432RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011433 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011434 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011435
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011436 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011437 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011438
11439 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000011440 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000011441 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
11442 // Get the script wrapper in a local handle before calling GetScriptWrapper,
11443 // because using
11444 // instances->set(i, *GetScriptWrapper(script))
11445 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
11446 // already have deferenced the instances handle.
11447 Handle<JSValue> wrapper = GetScriptWrapper(script);
11448 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011449 }
11450
11451 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011452 Handle<JSObject> result =
11453 isolate->factory()->NewJSObject(isolate->array_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011454 Handle<JSArray>::cast(result)->SetContent(*instances);
11455 return *result;
11456}
11457
11458
11459// Helper function used by Runtime_DebugReferencedBy below.
11460static int DebugReferencedBy(JSObject* target,
11461 Object* instance_filter, int max_references,
11462 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011463 JSFunction* arguments_function) {
11464 NoHandleAllocation ha;
11465 AssertNoAllocation no_alloc;
11466
11467 // Iterate the heap.
11468 int count = 0;
11469 JSObject* last = NULL;
11470 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011471 HeapObject* heap_obj = NULL;
11472 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011473 (max_references == 0 || count < max_references)) {
11474 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011475 if (heap_obj->IsJSObject()) {
11476 // Skip context extension objects and argument arrays as these are
11477 // checked in the context of functions using them.
11478 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000011479 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011480 obj->map()->constructor() == arguments_function) {
11481 continue;
11482 }
11483
11484 // Check if the JS object has a reference to the object looked for.
11485 if (obj->ReferencesObject(target)) {
11486 // Check instance filter if supplied. This is normally used to avoid
11487 // references from mirror objects (see Runtime_IsInPrototypeChain).
11488 if (!instance_filter->IsUndefined()) {
11489 Object* V = obj;
11490 while (true) {
11491 Object* prototype = V->GetPrototype();
11492 if (prototype->IsNull()) {
11493 break;
11494 }
11495 if (instance_filter == prototype) {
11496 obj = NULL; // Don't add this object.
11497 break;
11498 }
11499 V = prototype;
11500 }
11501 }
11502
11503 if (obj != NULL) {
11504 // Valid reference found add to instance array if supplied an update
11505 // count.
11506 if (instances != NULL && count < instances_size) {
11507 instances->set(count, obj);
11508 }
11509 last = obj;
11510 count++;
11511 }
11512 }
11513 }
11514 }
11515
11516 // Check for circular reference only. This can happen when the object is only
11517 // referenced from mirrors and has a circular reference in which case the
11518 // object is not really alive and would have been garbage collected if not
11519 // referenced from the mirror.
11520 if (count == 1 && last == target) {
11521 count = 0;
11522 }
11523
11524 // Return the number of referencing objects found.
11525 return count;
11526}
11527
11528
11529// Scan the heap for objects with direct references to an object
11530// args[0]: the object to find references to
11531// args[1]: constructor function for instances to exclude (Mirror)
11532// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011533RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011534 ASSERT(args.length() == 3);
11535
11536 // First perform a full GC in order to avoid references from dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011537 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011538
11539 // Check parameters.
11540 CONVERT_CHECKED(JSObject, target, args[0]);
11541 Object* instance_filter = args[1];
11542 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
11543 instance_filter->IsJSObject());
11544 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
11545 RUNTIME_ASSERT(max_references >= 0);
11546
11547 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011548 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011549 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011550 JSFunction* arguments_function =
11551 JSFunction::cast(arguments_boilerplate->map()->constructor());
11552
11553 // Get the number of referencing objects.
11554 int count;
11555 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011556 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011557
11558 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011559 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011560 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011561 if (!maybe_object->ToObject(&object)) return maybe_object;
11562 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011563 FixedArray* instances = FixedArray::cast(object);
11564
11565 // Fill the referencing objects.
11566 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011567 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011568
11569 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011570 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011571 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11572 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011573 if (!maybe_result->ToObject(&result)) return maybe_result;
11574 }
11575 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011576 return result;
11577}
11578
11579
11580// Helper function used by Runtime_DebugConstructedBy below.
11581static int DebugConstructedBy(JSFunction* constructor, int max_references,
11582 FixedArray* instances, int instances_size) {
11583 AssertNoAllocation no_alloc;
11584
11585 // Iterate the heap.
11586 int count = 0;
11587 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011588 HeapObject* heap_obj = NULL;
11589 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011590 (max_references == 0 || count < max_references)) {
11591 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011592 if (heap_obj->IsJSObject()) {
11593 JSObject* obj = JSObject::cast(heap_obj);
11594 if (obj->map()->constructor() == constructor) {
11595 // Valid reference found add to instance array if supplied an update
11596 // count.
11597 if (instances != NULL && count < instances_size) {
11598 instances->set(count, obj);
11599 }
11600 count++;
11601 }
11602 }
11603 }
11604
11605 // Return the number of referencing objects found.
11606 return count;
11607}
11608
11609
11610// Scan the heap for objects constructed by a specific function.
11611// args[0]: the constructor to find instances of
11612// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011613RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011614 ASSERT(args.length() == 2);
11615
11616 // First perform a full GC in order to avoid dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011617 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011618
11619 // Check parameters.
11620 CONVERT_CHECKED(JSFunction, constructor, args[0]);
11621 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
11622 RUNTIME_ASSERT(max_references >= 0);
11623
11624 // Get the number of referencing objects.
11625 int count;
11626 count = DebugConstructedBy(constructor, max_references, NULL, 0);
11627
11628 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011629 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011630 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011631 if (!maybe_object->ToObject(&object)) return maybe_object;
11632 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011633 FixedArray* instances = FixedArray::cast(object);
11634
11635 // Fill the referencing objects.
11636 count = DebugConstructedBy(constructor, max_references, instances, count);
11637
11638 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011639 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011640 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11641 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011642 if (!maybe_result->ToObject(&result)) return maybe_result;
11643 }
11644 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011645 return result;
11646}
11647
11648
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011649// Find the effective prototype object as returned by __proto__.
11650// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011651RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011652 ASSERT(args.length() == 1);
11653
11654 CONVERT_CHECKED(JSObject, obj, args[0]);
11655
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011656 // Use the __proto__ accessor.
11657 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011658}
11659
11660
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011661RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000011662 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011663 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011664 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011665}
11666
11667
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011668RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011669#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011670 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011671 ASSERT(args.length() == 1);
11672 // Get the function and make sure it is compiled.
11673 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011674 Handle<SharedFunctionInfo> shared(func->shared());
11675 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011676 return Failure::Exception();
11677 }
11678 func->code()->PrintLn();
11679#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011680 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011681}
ager@chromium.org9085a012009-05-11 19:22:57 +000011682
11683
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011684RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011685#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011686 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011687 ASSERT(args.length() == 1);
11688 // Get the function and make sure it is compiled.
11689 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011690 Handle<SharedFunctionInfo> shared(func->shared());
11691 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011692 return Failure::Exception();
11693 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011694 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011695#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011696 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011697}
11698
11699
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011700RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000011701 NoHandleAllocation ha;
11702 ASSERT(args.length() == 1);
11703
11704 CONVERT_CHECKED(JSFunction, f, args[0]);
11705 return f->shared()->inferred_name();
11706}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011707
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011708
11709static int FindSharedFunctionInfosForScript(Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011710 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011711 AssertNoAllocation no_allocations;
11712
11713 int counter = 0;
11714 int buffer_size = buffer->length();
11715 HeapIterator iterator;
11716 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
11717 ASSERT(obj != NULL);
11718 if (!obj->IsSharedFunctionInfo()) {
11719 continue;
11720 }
11721 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
11722 if (shared->script() != script) {
11723 continue;
11724 }
11725 if (counter < buffer_size) {
11726 buffer->set(counter, shared);
11727 }
11728 counter++;
11729 }
11730 return counter;
11731}
11732
11733// For a script finds all SharedFunctionInfo's in the heap that points
11734// to this script. Returns JSArray of SharedFunctionInfo wrapped
11735// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011736RUNTIME_FUNCTION(MaybeObject*,
11737 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011738 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011739 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011740 CONVERT_CHECKED(JSValue, script_value, args[0]);
11741
11742 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
11743
11744 const int kBufferSize = 32;
11745
11746 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011747 array = isolate->factory()->NewFixedArray(kBufferSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011748 int number = FindSharedFunctionInfosForScript(*script, *array);
11749 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011750 array = isolate->factory()->NewFixedArray(number);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011751 FindSharedFunctionInfosForScript(*script, *array);
11752 }
11753
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011754 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011755 result->set_length(Smi::FromInt(number));
11756
11757 LiveEdit::WrapSharedFunctionInfos(result);
11758
11759 return *result;
11760}
11761
11762// For a script calculates compilation information about all its functions.
11763// The script source is explicitly specified by the second argument.
11764// The source of the actual script is not used, however it is important that
11765// all generated code keeps references to this particular instance of script.
11766// Returns a JSArray of compilation infos. The array is ordered so that
11767// each function with all its descendant is always stored in a continues range
11768// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011769RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011770 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011771 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011772 CONVERT_CHECKED(JSValue, script, args[0]);
11773 CONVERT_ARG_CHECKED(String, source, 1);
11774 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
11775
11776 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
11777
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011778 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011779 return Failure::Exception();
11780 }
11781
11782 return result;
11783}
11784
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011785// Changes the source of the script to a new_source.
11786// If old_script_name is provided (i.e. is a String), also creates a copy of
11787// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011788RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011789 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011790 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011791 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
11792 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011793 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011794
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011795 CONVERT_CHECKED(Script, original_script_pointer,
11796 original_script_value->value());
11797 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011798
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011799 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
11800 new_source,
11801 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011802
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011803 if (old_script->IsScript()) {
11804 Handle<Script> script_handle(Script::cast(old_script));
11805 return *(GetScriptWrapper(script_handle));
11806 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011807 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011808 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011809}
11810
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011811
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011812RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011813 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011814 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011815 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
11816 return LiveEdit::FunctionSourceUpdated(shared_info);
11817}
11818
11819
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011820// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011821RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011822 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011823 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011824 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
11825 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
11826
ager@chromium.orgac091b72010-05-05 07:34:42 +000011827 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011828}
11829
11830// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011831RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011832 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011833 HandleScope scope(isolate);
11834 Handle<Object> function_object(args[0], isolate);
11835 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011836
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011837 if (function_object->IsJSValue()) {
11838 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
11839 if (script_object->IsJSValue()) {
11840 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011841 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011842 }
11843
11844 LiveEdit::SetFunctionScript(function_wrapper, script_object);
11845 } else {
11846 // Just ignore this. We may not have a SharedFunctionInfo for some functions
11847 // and we check it in this function.
11848 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011849
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011850 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011851}
11852
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011853
11854// In a code of a parent function replaces original function as embedded object
11855// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011856RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011857 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011858 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011859
11860 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
11861 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
11862 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
11863
11864 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
11865 subst_wrapper);
11866
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011867 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011868}
11869
11870
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011871// Updates positions of a shared function info (first parameter) according
11872// to script source change. Text change is described in second parameter as
11873// array of groups of 3 numbers:
11874// (change_begin, change_end, change_end_new_position).
11875// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011876RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011877 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011878 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011879 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
11880 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
11881
ager@chromium.orgac091b72010-05-05 07:34:42 +000011882 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011883}
11884
11885
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011886// For array of SharedFunctionInfo's (each wrapped in JSValue)
11887// checks that none of them have activations on stacks (of any thread).
11888// Returns array of the same length with corresponding results of
11889// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011890RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011891 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011892 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011893 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000011894 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011895
ager@chromium.org357bf652010-04-12 11:30:10 +000011896 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011897}
11898
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011899// Compares 2 strings line-by-line, then token-wise and returns diff in form
11900// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
11901// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011902RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011903 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011904 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011905 CONVERT_ARG_CHECKED(String, s1, 0);
11906 CONVERT_ARG_CHECKED(String, s2, 1);
11907
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011908 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011909}
11910
11911
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011912// A testing entry. Returns statement position which is the closest to
11913// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011914RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011915 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011916 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011917 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11918 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11919
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011920 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011921
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011922 if (code->kind() != Code::FUNCTION &&
11923 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011924 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011925 }
11926
11927 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011928 int closest_pc = 0;
11929 int distance = kMaxInt;
11930 while (!it.done()) {
11931 int statement_position = static_cast<int>(it.rinfo()->data());
11932 // Check if this break point is closer that what was previously found.
11933 if (source_position <= statement_position &&
11934 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000011935 closest_pc =
11936 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011937 distance = statement_position - source_position;
11938 // Check whether we can't get any closer.
11939 if (distance == 0) break;
11940 }
11941 it.next();
11942 }
11943
11944 return Smi::FromInt(closest_pc);
11945}
11946
11947
ager@chromium.org357bf652010-04-12 11:30:10 +000011948// Calls specified function with or without entering the debugger.
11949// This is used in unit tests to run code as if debugger is entered or simply
11950// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011951RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011952 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011953 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000011954 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11955 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
11956
11957 Handle<Object> result;
11958 bool pending_exception;
11959 {
11960 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011961 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011962 &pending_exception);
11963 } else {
11964 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011965 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011966 &pending_exception);
11967 }
11968 }
11969 if (!pending_exception) {
11970 return *result;
11971 } else {
11972 return Failure::Exception();
11973 }
11974}
11975
11976
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011977// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011978RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011979 CONVERT_CHECKED(String, arg, args[0]);
11980 SmartPointer<char> flags =
11981 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
11982 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011983 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011984}
11985
11986
11987// Performs a GC.
11988// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011989RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011990 isolate->heap()->CollectAllGarbage(true);
11991 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011992}
11993
11994
11995// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011996RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011997 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011998 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011999 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012000 }
12001 return Smi::FromInt(usage);
12002}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012003
12004
12005// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012006RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012007#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012008 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012009#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012010 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012011#endif
12012}
12013
12014
12015// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012016RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012017#ifdef LIVE_OBJECT_LIST
12018 return LiveObjectList::Capture();
12019#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012020 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012021#endif
12022}
12023
12024
12025// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012026RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012027#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012028 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012029 bool success = LiveObjectList::Delete(id);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012030 return success ? isolate->heap()->true_value() :
12031 isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012032#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012033 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012034#endif
12035}
12036
12037
12038// Generates the response to a debugger request for a dump of the objects
12039// contained in the difference between the captured live object lists
12040// specified by id1 and id2.
12041// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12042// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012043RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012044#ifdef LIVE_OBJECT_LIST
12045 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012046 CONVERT_SMI_ARG_CHECKED(id1, 0);
12047 CONVERT_SMI_ARG_CHECKED(id2, 1);
12048 CONVERT_SMI_ARG_CHECKED(start, 2);
12049 CONVERT_SMI_ARG_CHECKED(count, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012050 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
12051 EnterDebugger enter_debugger;
12052 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12053#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012054 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012055#endif
12056}
12057
12058
12059// Gets the specified object as requested by the debugger.
12060// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012061RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012062#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012063 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012064 Object* result = LiveObjectList::GetObj(obj_id);
12065 return result;
12066#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012067 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012068#endif
12069}
12070
12071
12072// Gets the obj id for the specified address if valid.
12073// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012074RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012075#ifdef LIVE_OBJECT_LIST
12076 HandleScope scope;
12077 CONVERT_ARG_CHECKED(String, address, 0);
12078 Object* result = LiveObjectList::GetObjId(address);
12079 return result;
12080#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012081 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012082#endif
12083}
12084
12085
12086// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012087RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012088#ifdef LIVE_OBJECT_LIST
12089 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012090 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012091 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12092 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12093 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12094 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
12095 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
12096
12097 Handle<JSObject> instance_filter;
12098 if (args[1]->IsJSObject()) {
12099 instance_filter = args.at<JSObject>(1);
12100 }
12101 bool verbose = false;
12102 if (args[2]->IsBoolean()) {
12103 verbose = args[2]->IsTrue();
12104 }
12105 int start = 0;
12106 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012107 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012108 }
12109 int limit = Smi::kMaxValue;
12110 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012111 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012112 }
12113
12114 return LiveObjectList::GetObjRetainers(obj_id,
12115 instance_filter,
12116 verbose,
12117 start,
12118 limit,
12119 filter_obj);
12120#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012121 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012122#endif
12123}
12124
12125
12126// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012127RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012128#ifdef LIVE_OBJECT_LIST
12129 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012130 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
12131 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012132 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
12133
12134 Handle<JSObject> instance_filter;
12135 if (args[2]->IsJSObject()) {
12136 instance_filter = args.at<JSObject>(2);
12137 }
12138
12139 Object* result =
12140 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
12141 return result;
12142#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012143 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012144#endif
12145}
12146
12147
12148// Generates the response to a debugger request for a list of all
12149// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012150RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012151#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012152 CONVERT_SMI_ARG_CHECKED(start, 0);
12153 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012154 return LiveObjectList::Info(start, count);
12155#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012156 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012157#endif
12158}
12159
12160
12161// Gets a dump of the specified object as requested by the debugger.
12162// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012163RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012164#ifdef LIVE_OBJECT_LIST
12165 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012166 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012167 Object* result = LiveObjectList::PrintObj(obj_id);
12168 return result;
12169#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012170 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012171#endif
12172}
12173
12174
12175// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012176RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012177#ifdef LIVE_OBJECT_LIST
12178 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012179 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012180#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012181 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012182#endif
12183}
12184
12185
12186// Generates the response to a debugger request for a summary of the types
12187// of objects in the difference between the captured live object lists
12188// specified by id1 and id2.
12189// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12190// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012191RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012192#ifdef LIVE_OBJECT_LIST
12193 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012194 CONVERT_SMI_ARG_CHECKED(id1, 0);
12195 CONVERT_SMI_ARG_CHECKED(id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012196 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
12197
12198 EnterDebugger enter_debugger;
12199 return LiveObjectList::Summarize(id1, id2, filter_obj);
12200#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012201 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012202#endif
12203}
12204
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012205#endif // ENABLE_DEBUGGER_SUPPORT
12206
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012207
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012208RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012209 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012210 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012211 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012212}
12213
12214
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012215RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012216 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012217 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012218 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012219}
12220
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012221
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012222// Finds the script object from the script data. NOTE: This operation uses
12223// heap traversal to find the function generated for the source position
12224// for the requested break point. For lazily compiled functions several heap
12225// traversals might be required rendering this operation as a rather slow
12226// operation. However for setting break points which is normally done through
12227// some kind of user interaction the performance is not crucial.
12228static Handle<Object> Runtime_GetScriptFromScriptName(
12229 Handle<String> script_name) {
12230 // Scan the heap for Script objects to find the script with the requested
12231 // script data.
12232 Handle<Script> script;
12233 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012234 HeapObject* obj = NULL;
12235 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012236 // If a script is found check if it has the script data requested.
12237 if (obj->IsScript()) {
12238 if (Script::cast(obj)->name()->IsString()) {
12239 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
12240 script = Handle<Script>(Script::cast(obj));
12241 }
12242 }
12243 }
12244 }
12245
12246 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012247 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012248
12249 // Return the script found.
12250 return GetScriptWrapper(script);
12251}
12252
12253
12254// Get the script object from script data. NOTE: Regarding performance
12255// see the NOTE for GetScriptFromScriptData.
12256// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012257RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012258 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012259
12260 ASSERT(args.length() == 1);
12261
12262 CONVERT_CHECKED(String, script_name, args[0]);
12263
12264 // Find the requested script.
12265 Handle<Object> result =
12266 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
12267 return *result;
12268}
12269
12270
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012271// Determines whether the given stack frame should be displayed in
12272// a stack trace. The caller is the error constructor that asked
12273// for the stack trace to be collected. The first time a construct
12274// call to this function is encountered it is skipped. The seen_caller
12275// in/out parameter is used to remember if the caller has been seen
12276// yet.
12277static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
12278 bool* seen_caller) {
12279 // Only display JS frames.
12280 if (!raw_frame->is_java_script())
12281 return false;
12282 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
12283 Object* raw_fun = frame->function();
12284 // Not sure when this can happen but skip it just in case.
12285 if (!raw_fun->IsJSFunction())
12286 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012287 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012288 *seen_caller = true;
12289 return false;
12290 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012291 // Skip all frames until we've seen the caller. Also, skip the most
12292 // obvious builtin calls. Some builtin calls (such as Number.ADD
12293 // which is invoked using 'call') are very difficult to recognize
12294 // so we're leaving them in for now.
12295 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012296}
12297
12298
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012299// Collect the raw data for a stack trace. Returns an array of 4
12300// element segments each containing a receiver, function, code and
12301// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012302RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012303 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012304 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012305 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
12306
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012307 HandleScope scope(isolate);
12308 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012309
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000012310 limit = Max(limit, 0); // Ensure that limit is not negative.
12311 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012312 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012313 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012314
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012315 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012316 // If the caller parameter is a function we skip frames until we're
12317 // under it before starting to collect.
12318 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012319 int cursor = 0;
12320 int frames_seen = 0;
12321 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012322 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012323 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012324 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012325 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012326 // Set initial size to the maximum inlining level + 1 for the outermost
12327 // function.
12328 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012329 frame->Summarize(&frames);
12330 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012331 if (cursor + 4 > elements->length()) {
12332 int new_capacity = JSObject::NewElementsCapacity(elements->length());
12333 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012334 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012335 for (int i = 0; i < cursor; i++) {
12336 new_elements->set(i, elements->get(i));
12337 }
12338 elements = new_elements;
12339 }
12340 ASSERT(cursor + 4 <= elements->length());
12341
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012342 Handle<Object> recv = frames[i].receiver();
12343 Handle<JSFunction> fun = frames[i].function();
12344 Handle<Code> code = frames[i].code();
12345 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012346 elements->set(cursor++, *recv);
12347 elements->set(cursor++, *fun);
12348 elements->set(cursor++, *code);
12349 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012350 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012351 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012352 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012353 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012354 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012355 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012356 return *result;
12357}
12358
12359
ager@chromium.org3811b432009-10-28 14:53:37 +000012360// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012361RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000012362 ASSERT_EQ(args.length(), 0);
12363
12364 NoHandleAllocation ha;
12365
12366 const char* version_string = v8::V8::GetVersion();
12367
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012368 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
12369 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000012370}
12371
12372
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012373RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012374 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012375 OS::PrintError("abort: %s\n",
12376 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012377 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012378 OS::Abort();
12379 UNREACHABLE();
12380 return NULL;
12381}
12382
12383
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012384RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012385 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012386 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012387 Object* key = args[1];
12388
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012389 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012390 Object* o = cache->get(finger_index);
12391 if (o == key) {
12392 // The fastest case: hit the same place again.
12393 return cache->get(finger_index + 1);
12394 }
12395
12396 for (int i = finger_index - 2;
12397 i >= JSFunctionResultCache::kEntriesIndex;
12398 i -= 2) {
12399 o = cache->get(i);
12400 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012401 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012402 return cache->get(i + 1);
12403 }
12404 }
12405
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012406 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012407 ASSERT(size <= cache->length());
12408
12409 for (int i = size - 2; i > finger_index; i -= 2) {
12410 o = cache->get(i);
12411 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012412 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012413 return cache->get(i + 1);
12414 }
12415 }
12416
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012417 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012418 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012419
12420 Handle<JSFunctionResultCache> cache_handle(cache);
12421 Handle<Object> key_handle(key);
12422 Handle<Object> value;
12423 {
12424 Handle<JSFunction> factory(JSFunction::cast(
12425 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
12426 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012427 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012428 // This handle is nor shared, nor used later, so it's safe.
12429 Object** argv[] = { key_handle.location() };
12430 bool pending_exception = false;
12431 value = Execution::Call(factory,
12432 receiver,
12433 1,
12434 argv,
12435 &pending_exception);
12436 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012437 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012438
12439#ifdef DEBUG
12440 cache_handle->JSFunctionResultCacheVerify();
12441#endif
12442
12443 // Function invocation may have cleared the cache. Reread all the data.
12444 finger_index = cache_handle->finger_index();
12445 size = cache_handle->size();
12446
12447 // If we have spare room, put new data into it, otherwise evict post finger
12448 // entry which is likely to be the least recently used.
12449 int index = -1;
12450 if (size < cache_handle->length()) {
12451 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
12452 index = size;
12453 } else {
12454 index = finger_index + JSFunctionResultCache::kEntrySize;
12455 if (index == cache_handle->length()) {
12456 index = JSFunctionResultCache::kEntriesIndex;
12457 }
12458 }
12459
12460 ASSERT(index % 2 == 0);
12461 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
12462 ASSERT(index < cache_handle->length());
12463
12464 cache_handle->set(index, *key_handle);
12465 cache_handle->set(index + 1, *value);
12466 cache_handle->set_finger_index(index);
12467
12468#ifdef DEBUG
12469 cache_handle->JSFunctionResultCacheVerify();
12470#endif
12471
12472 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012473}
12474
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012475
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012476RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012477 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012478 CONVERT_ARG_CHECKED(String, type, 0);
12479 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012480 return *isolate->factory()->NewJSMessageObject(
12481 type,
12482 arguments,
12483 0,
12484 0,
12485 isolate->factory()->undefined_value(),
12486 isolate->factory()->undefined_value(),
12487 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012488}
12489
12490
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012491RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012492 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12493 return message->type();
12494}
12495
12496
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012497RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012498 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12499 return message->arguments();
12500}
12501
12502
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012503RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012504 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12505 return Smi::FromInt(message->start_position());
12506}
12507
12508
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012509RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012510 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12511 return message->script();
12512}
12513
12514
kasper.lund44510672008-07-25 07:37:58 +000012515#ifdef DEBUG
12516// ListNatives is ONLY used by the fuzz-natives.js in debug mode
12517// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012518RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000012519 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012520 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012521#define COUNT_ENTRY(Name, argc, ressize) + 1
12522 int entry_count = 0
12523 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
12524 INLINE_FUNCTION_LIST(COUNT_ENTRY)
12525 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
12526#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012527 Factory* factory = isolate->factory();
12528 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012529 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012530 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000012531#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012532 { \
12533 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012534 Handle<String> name; \
12535 /* Inline runtime functions have an underscore in front of the name. */ \
12536 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012537 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012538 Vector<const char>("_" #Name, StrLength("_" #Name))); \
12539 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012540 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012541 Vector<const char>(#Name, StrLength(#Name))); \
12542 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012543 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012544 pair_elements->set(0, *name); \
12545 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012546 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012547 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012548 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012549 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012550 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012551 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012552 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012553 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012554#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012555 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012556 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012557 return *result;
12558}
kasper.lund44510672008-07-25 07:37:58 +000012559#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012560
12561
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012562RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012563 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012564 CONVERT_CHECKED(String, format, args[0]);
12565 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012566 Vector<const char> chars = format->ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012567 LOGGER->LogRuntime(chars, elms);
12568 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012569}
12570
12571
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012572RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012573 UNREACHABLE(); // implemented as macro in the parser
12574 return NULL;
12575}
12576
12577
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012578#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
12579 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
12580 CONVERT_CHECKED(JSObject, obj, args[0]); \
12581 return isolate->heap()->ToBoolean(obj->Has##Name()); \
12582 }
12583
12584ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
12585ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
12586ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
12587ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
12588ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
12589ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
12590ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
12591ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
12592ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
12593ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
12594ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
12595ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
12596ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
12597
12598#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
12599
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012600// ----------------------------------------------------------------------------
12601// Implementation of Runtime
12602
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012603#define F(name, number_of_args, result_size) \
12604 { Runtime::k##name, Runtime::RUNTIME, #name, \
12605 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012606
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012607
12608#define I(name, number_of_args, result_size) \
12609 { Runtime::kInline##name, Runtime::INLINE, \
12610 "_" #name, NULL, number_of_args, result_size },
12611
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012612static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012613 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012614 INLINE_FUNCTION_LIST(I)
12615 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012616};
12617
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012618
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012619MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
12620 Object* dictionary) {
12621 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012622 ASSERT(dictionary != NULL);
12623 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
12624 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000012625 Object* name_symbol;
12626 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012627 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012628 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
12629 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012630 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012631 { MaybeObject* maybe_dictionary = string_dictionary->Add(
12632 String::cast(name_symbol),
12633 Smi::FromInt(i),
12634 PropertyDetails(NONE, NORMAL));
12635 if (!maybe_dictionary->ToObject(&dictionary)) {
12636 // Non-recoverable failure. Calling code must restart heap
12637 // initialization.
12638 return maybe_dictionary;
12639 }
12640 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012641 }
12642 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012643}
12644
12645
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012646const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
12647 Heap* heap = name->GetHeap();
12648 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012649 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012650 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012651 int function_index = Smi::cast(smi_index)->value();
12652 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012653 }
12654 return NULL;
12655}
12656
12657
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012658const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012659 return &(kIntrinsicFunctions[static_cast<int>(id)]);
12660}
12661
12662
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012663void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012664 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012665 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012666 if (failure->IsRetryAfterGC()) {
12667 // Try to do a garbage collection; ignore it if it fails. The C
12668 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012669 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012670 } else {
12671 // Handle last resort GC and make sure to allow future allocations
12672 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012673 isolate->counters()->gc_last_resort_from_js()->Increment();
12674 isolate->heap()->CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012675 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012676}
12677
12678
12679} } // namespace v8::internal