blob: 8c43d64536c380f3d5d33a7214c332d306931042 [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 }
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000222 case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
223 UNIMPLEMENTED();
224 break;
225 case JSObject::EXTERNAL_PIXEL_ELEMENTS:
226 case JSObject::EXTERNAL_BYTE_ELEMENTS:
227 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
228 case JSObject::EXTERNAL_SHORT_ELEMENTS:
229 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
230 case JSObject::EXTERNAL_INT_ELEMENTS:
231 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
232 case JSObject::EXTERNAL_FLOAT_ELEMENTS:
233 case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
234 case JSObject::FAST_DOUBLE_ELEMENTS:
235 // No contained objects, nothing to do.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000236 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000237 }
238 return copy;
239}
240
241
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000242RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000243 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000244 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000245}
246
247
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000248RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000249 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000250 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000251}
252
253
ager@chromium.org236ad962008-09-25 09:45:57 +0000254static Handle<Map> ComputeObjectLiteralMap(
255 Handle<Context> context,
256 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000257 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000258 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000259 int properties_length = constant_properties->length();
260 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000261 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000262 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000263 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000264 for (int p = 0; p != properties_length; p += 2) {
265 Object* key = constant_properties->get(p);
266 uint32_t element_index = 0;
267 if (key->IsSymbol()) {
268 number_of_symbol_keys++;
269 } else if (key->ToArrayIndex(&element_index)) {
270 // An index key does not require space in the property backing store.
271 number_of_properties--;
272 } else {
273 // Bail out as a non-symbol non-index key makes caching impossible.
274 // ASSERT to make sure that the if condition after the loop is false.
275 ASSERT(number_of_symbol_keys != number_of_properties);
276 break;
277 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000278 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000279 // If we only have symbols and array indices among keys then we can
280 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000281 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000282 if ((number_of_symbol_keys == number_of_properties) &&
283 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000284 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000285 Handle<FixedArray> keys =
286 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000287 if (number_of_symbol_keys > 0) {
288 int index = 0;
289 for (int p = 0; p < properties_length; p += 2) {
290 Object* key = constant_properties->get(p);
291 if (key->IsSymbol()) {
292 keys->set(index++, key);
293 }
294 }
295 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000296 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000297 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000298 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000299 }
300 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000301 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000302 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000303 Handle<Map>(context->object_function()->initial_map()),
304 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000305}
306
307
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000308static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000309 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000310 Handle<FixedArray> literals,
311 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000312
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000313
314static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000315 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000316 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000317 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000318 bool should_have_fast_elements,
319 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000320 // Get the global context from the literals array. This is the
321 // context in which the function was created and we use the object
322 // function from this context to create the object literal. We do
323 // not use the object function from the current global context
324 // because this might be the object function from another context
325 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000326 Handle<Context> context =
327 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
328
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000329 // In case we have function literals, we want the object to be in
330 // slow properties mode for now. We don't go in the map cache because
331 // maps with constant functions can't be shared if the functions are
332 // not the same (which is the common case).
333 bool is_result_from_cache = false;
334 Handle<Map> map = has_function_literal
335 ? Handle<Map>(context->object_function()->initial_map())
336 : ComputeObjectLiteralMap(context,
337 constant_properties,
338 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000339
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000340 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000341
342 // Normalize the elements of the boilerplate to save space if needed.
343 if (!should_have_fast_elements) NormalizeElements(boilerplate);
344
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000345 // Add the constant properties to the boilerplate.
346 int length = constant_properties->length();
347 bool should_transform =
348 !is_result_from_cache && boilerplate->HasFastProperties();
349 if (should_transform || has_function_literal) {
350 // Normalize the properties of object to avoid n^2 behavior
351 // when extending the object multiple properties. Indicate the number of
352 // properties to be added.
353 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
354 }
355
356 for (int index = 0; index < length; index +=2) {
357 Handle<Object> key(constant_properties->get(index+0), isolate);
358 Handle<Object> value(constant_properties->get(index+1), isolate);
359 if (value->IsFixedArray()) {
360 // The value contains the constant_properties of a
361 // simple object or array literal.
362 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
363 value = CreateLiteralBoilerplate(isolate, literals, array);
364 if (value.is_null()) return value;
365 }
366 Handle<Object> result;
367 uint32_t element_index = 0;
368 if (key->IsSymbol()) {
369 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
370 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000371 result = SetOwnElement(boilerplate,
372 element_index,
373 value,
374 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000375 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000376 Handle<String> name(String::cast(*key));
377 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000378 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
379 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000380 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000381 } else if (key->ToArrayIndex(&element_index)) {
382 // Array index (uint32).
383 result = SetOwnElement(boilerplate,
384 element_index,
385 value,
386 kNonStrictMode);
387 } else {
388 // Non-uint32 number.
389 ASSERT(key->IsNumber());
390 double num = key->Number();
391 char arr[100];
392 Vector<char> buffer(arr, ARRAY_SIZE(arr));
393 const char* str = DoubleToCString(num, buffer);
394 Handle<String> name =
395 isolate->factory()->NewStringFromAscii(CStrVector(str));
396 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
397 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000398 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000399 // If setting the property on the boilerplate throws an
400 // exception, the exception is converted to an empty handle in
401 // the handle based operations. In that case, we need to
402 // convert back to an exception.
403 if (result.is_null()) return result;
404 }
405
406 // Transform to fast properties if necessary. For object literals with
407 // containing function literals we defer this operation until after all
408 // computed properties have been assigned so that we can generate
409 // constant function properties.
410 if (should_transform && !has_function_literal) {
411 TransformToFastProperties(boilerplate,
412 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000413 }
414
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000415 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000416}
417
418
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000419static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000420 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000421 Handle<FixedArray> literals,
422 Handle<FixedArray> elements) {
423 // Create the JSArray.
424 Handle<JSFunction> constructor(
425 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000426 Handle<Object> object = isolate->factory()->NewJSObject(constructor);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000427
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000428 const bool is_cow =
429 (elements->map() == isolate->heap()->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000430 Handle<FixedArray> copied_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000431 is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000432
433 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000434 if (is_cow) {
435#ifdef DEBUG
436 // Copy-on-write arrays must be shallow (and simple).
437 for (int i = 0; i < content->length(); i++) {
438 ASSERT(!content->get(i)->IsFixedArray());
439 }
440#endif
441 } else {
442 for (int i = 0; i < content->length(); i++) {
443 if (content->get(i)->IsFixedArray()) {
444 // The value contains the constant_properties of a
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000445 // simple object or array literal.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000446 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
447 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000448 CreateLiteralBoilerplate(isolate, literals, fa);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000449 if (result.is_null()) return result;
450 content->set(i, *result);
451 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000452 }
453 }
454
455 // Set the elements.
456 Handle<JSArray>::cast(object)->SetContent(*content);
457 return object;
458}
459
460
461static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000462 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000463 Handle<FixedArray> literals,
464 Handle<FixedArray> array) {
465 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000466 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000467 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000468 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000469 return CreateObjectLiteralBoilerplate(isolate,
470 literals,
471 elements,
472 true,
473 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000474 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000475 return CreateObjectLiteralBoilerplate(isolate,
476 literals,
477 elements,
478 false,
479 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000480 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000481 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000482 default:
483 UNREACHABLE();
484 return Handle<Object>::null();
485 }
486}
487
488
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000489RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000490 // Takes a FixedArray of elements containing the literal elements of
491 // the array literal and produces JSArray with those elements.
492 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000493 // which contains the context from which to get the Array function
494 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000495 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000496 ASSERT(args.length() == 3);
497 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000498 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000499 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000500
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000501 Handle<Object> object =
502 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000503 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000504
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000505 // Update the functions literal and return the boilerplate.
506 literals->set(literals_index, *object);
507 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000508}
509
510
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000511RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000512 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000513 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000514 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000515 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000516 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000517 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000518 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
519 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000520
521 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000522 Handle<Object> boilerplate(literals->get(literals_index), isolate);
523 if (*boilerplate == isolate->heap()->undefined_value()) {
524 boilerplate = CreateObjectLiteralBoilerplate(isolate,
525 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000526 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000527 should_have_fast_elements,
528 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000529 if (boilerplate.is_null()) return Failure::Exception();
530 // Update the functions literal and return the boilerplate.
531 literals->set(literals_index, *boilerplate);
532 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000533 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000534}
535
536
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000537RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000538 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000539 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000540 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000541 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000542 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000543 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000544 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
545 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000546
547 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000548 Handle<Object> boilerplate(literals->get(literals_index), isolate);
549 if (*boilerplate == isolate->heap()->undefined_value()) {
550 boilerplate = CreateObjectLiteralBoilerplate(isolate,
551 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000552 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000553 should_have_fast_elements,
554 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000555 if (boilerplate.is_null()) return Failure::Exception();
556 // Update the functions literal and return the boilerplate.
557 literals->set(literals_index, *boilerplate);
558 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000559 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000560}
561
562
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000563RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000564 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000565 ASSERT(args.length() == 3);
566 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000567 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000568 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
569
570 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000571 Handle<Object> boilerplate(literals->get(literals_index), isolate);
572 if (*boilerplate == isolate->heap()->undefined_value()) {
573 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000574 if (boilerplate.is_null()) return Failure::Exception();
575 // Update the functions literal and return the boilerplate.
576 literals->set(literals_index, *boilerplate);
577 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000578 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000579}
580
581
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000582RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000583 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000584 ASSERT(args.length() == 3);
585 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000586 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000587 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
588
589 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000590 Handle<Object> boilerplate(literals->get(literals_index), isolate);
591 if (*boilerplate == isolate->heap()->undefined_value()) {
592 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000593 if (boilerplate.is_null()) return Failure::Exception();
594 // Update the functions literal and return the boilerplate.
595 literals->set(literals_index, *boilerplate);
596 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000597 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000598 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000599 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000600 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000601 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000602}
603
604
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000605RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
606 ASSERT(args.length() == 2);
607 Object* handler = args[0];
608 Object* prototype = args[1];
609 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000610 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000611 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
612}
613
614
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000615RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
616 ASSERT(args.length() == 1);
617 Object* obj = args[0];
618 return obj->IsJSProxy()
619 ? isolate->heap()->true_value() : isolate->heap()->false_value();
620}
621
622
623RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
624 ASSERT(args.length() == 1);
625 CONVERT_CHECKED(JSProxy, proxy, args[0]);
626 return proxy->handler();
627}
628
629
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000630RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
631 ASSERT(args.length() == 1);
632 CONVERT_CHECKED(JSProxy, proxy, args[0]);
633 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000634 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000635}
636
637
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000638RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000639 NoHandleAllocation ha;
640 ASSERT(args.length() == 1);
641 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000642 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000643 return JSObject::cast(obj)->class_name();
644}
645
ager@chromium.org7c537e22008-10-16 08:43:32 +0000646
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000647RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
648 NoHandleAllocation ha;
649 ASSERT(args.length() == 1);
650 Object* obj = args[0];
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000651 do {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000652 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000653 } while (obj->IsJSObject() &&
654 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000655 return obj;
656}
657
658
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000659RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000660 NoHandleAllocation ha;
661 ASSERT(args.length() == 2);
662 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
663 Object* O = args[0];
664 Object* V = args[1];
665 while (true) {
666 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000667 if (prototype->IsNull()) return isolate->heap()->false_value();
668 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000669 V = prototype;
670 }
671}
672
673
ager@chromium.org9085a012009-05-11 19:22:57 +0000674// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000675RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000676 NoHandleAllocation ha;
677 ASSERT(args.length() == 2);
678 CONVERT_CHECKED(JSObject, jsobject, args[0]);
679 CONVERT_CHECKED(JSObject, proto, args[1]);
680
681 // Sanity checks. The old prototype (that we are replacing) could
682 // theoretically be null, but if it is not null then check that we
683 // didn't already install a hidden prototype here.
684 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
685 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
686 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
687
688 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000689 Object* map_or_failure;
690 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
691 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
692 return maybe_map_or_failure;
693 }
694 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000695 Map* new_proto_map = Map::cast(map_or_failure);
696
lrn@chromium.org303ada72010-10-27 09:33:13 +0000697 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
698 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
699 return maybe_map_or_failure;
700 }
701 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000702 Map* new_map = Map::cast(map_or_failure);
703
704 // Set proto's prototype to be the old prototype of the object.
705 new_proto_map->set_prototype(jsobject->GetPrototype());
706 proto->set_map(new_proto_map);
707 new_proto_map->set_is_hidden_prototype();
708
709 // Set the object's prototype to proto.
710 new_map->set_prototype(proto);
711 jsobject->set_map(new_map);
712
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000713 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000714}
715
716
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000717RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000718 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000719 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000720 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000721 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000722}
723
724
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000725// Recursively traverses hidden prototypes if property is not found
726static void GetOwnPropertyImplementation(JSObject* obj,
727 String* name,
728 LookupResult* result) {
729 obj->LocalLookupRealNamedProperty(name, result);
730
731 if (!result->IsProperty()) {
732 Object* proto = obj->GetPrototype();
733 if (proto->IsJSObject() &&
734 JSObject::cast(proto)->map()->is_hidden_prototype())
735 GetOwnPropertyImplementation(JSObject::cast(proto),
736 name, result);
737 }
738}
739
740
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000741static bool CheckAccessException(LookupResult* result,
742 v8::AccessType access_type) {
743 if (result->type() == CALLBACKS) {
744 Object* callback = result->GetCallbackObject();
745 if (callback->IsAccessorInfo()) {
746 AccessorInfo* info = AccessorInfo::cast(callback);
747 bool can_access =
748 (access_type == v8::ACCESS_HAS &&
749 (info->all_can_read() || info->all_can_write())) ||
750 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
751 (access_type == v8::ACCESS_SET && info->all_can_write());
752 return can_access;
753 }
754 }
755
756 return false;
757}
758
759
760static bool CheckAccess(JSObject* obj,
761 String* name,
762 LookupResult* result,
763 v8::AccessType access_type) {
764 ASSERT(result->IsProperty());
765
766 JSObject* holder = result->holder();
767 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000768 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000769 while (true) {
770 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000771 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000772 // Access check callback denied the access, but some properties
773 // can have a special permissions which override callbacks descision
774 // (currently see v8::AccessControl).
775 break;
776 }
777
778 if (current == holder) {
779 return true;
780 }
781
782 current = JSObject::cast(current->GetPrototype());
783 }
784
785 // API callbacks can have per callback access exceptions.
786 switch (result->type()) {
787 case CALLBACKS: {
788 if (CheckAccessException(result, access_type)) {
789 return true;
790 }
791 break;
792 }
793 case INTERCEPTOR: {
794 // If the object has an interceptor, try real named properties.
795 // Overwrite the result to fetch the correct property later.
796 holder->LookupRealNamedProperty(name, result);
797 if (result->IsProperty()) {
798 if (CheckAccessException(result, access_type)) {
799 return true;
800 }
801 }
802 break;
803 }
804 default:
805 break;
806 }
807
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000808 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000809 return false;
810}
811
812
813// TODO(1095): we should traverse hidden prototype hierachy as well.
814static bool CheckElementAccess(JSObject* obj,
815 uint32_t index,
816 v8::AccessType access_type) {
817 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000818 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000819 return false;
820 }
821
822 return true;
823}
824
825
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000826// Enumerator used as indices into the array returned from GetOwnProperty
827enum PropertyDescriptorIndices {
828 IS_ACCESSOR_INDEX,
829 VALUE_INDEX,
830 GETTER_INDEX,
831 SETTER_INDEX,
832 WRITABLE_INDEX,
833 ENUMERABLE_INDEX,
834 CONFIGURABLE_INDEX,
835 DESCRIPTOR_SIZE
836};
837
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000838// Returns an array with the property description:
839// if args[1] is not a property on args[0]
840// returns undefined
841// if args[1] is a data property on args[0]
842// [false, value, Writeable, Enumerable, Configurable]
843// if args[1] is an accessor on args[0]
844// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000845RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000846 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000847 Heap* heap = isolate->heap();
848 HandleScope scope(isolate);
849 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
850 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000851 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000852 CONVERT_ARG_CHECKED(JSObject, obj, 0);
853 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000854
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000855 // This could be an element.
856 uint32_t index;
857 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000858 switch (obj->HasLocalElement(index)) {
859 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000860 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000861
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000862 case JSObject::STRING_CHARACTER_ELEMENT: {
863 // Special handling of string objects according to ECMAScript 5
864 // 15.5.5.2. Note that this might be a string object with elements
865 // other than the actual string value. This is covered by the
866 // subsequent cases.
867 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
868 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000869 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000870
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000871 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000872 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000873 elms->set(WRITABLE_INDEX, heap->false_value());
874 elms->set(ENUMERABLE_INDEX, heap->false_value());
875 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000876 return *desc;
877 }
878
879 case JSObject::INTERCEPTED_ELEMENT:
880 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000881 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000882 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000883 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000884 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000885 elms->set(WRITABLE_INDEX, heap->true_value());
886 elms->set(ENUMERABLE_INDEX, heap->true_value());
887 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000888 return *desc;
889 }
890
891 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000892 Handle<JSObject> holder = obj;
893 if (obj->IsJSGlobalProxy()) {
894 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000895 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000896 ASSERT(proto->IsJSGlobalObject());
897 holder = Handle<JSObject>(JSObject::cast(proto));
898 }
whesse@chromium.org7b260152011-06-20 15:33:18 +0000899 FixedArray* elements = FixedArray::cast(holder->elements());
900 NumberDictionary* dictionary = NULL;
901 if (elements->map() == heap->non_strict_arguments_elements_map()) {
902 dictionary = NumberDictionary::cast(elements->get(1));
903 } else {
904 dictionary = NumberDictionary::cast(elements);
905 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000906 int entry = dictionary->FindEntry(index);
907 ASSERT(entry != NumberDictionary::kNotFound);
908 PropertyDetails details = dictionary->DetailsAt(entry);
909 switch (details.type()) {
910 case CALLBACKS: {
911 // This is an accessor property with getter and/or setter.
912 FixedArray* callbacks =
913 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000914 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000915 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
916 elms->set(GETTER_INDEX, callbacks->get(0));
917 }
918 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
919 elms->set(SETTER_INDEX, callbacks->get(1));
920 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000921 break;
922 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000923 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000924 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000925 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000926 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000927 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000928 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000929 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000930 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000931 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000932 default:
933 UNREACHABLE();
934 break;
935 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000936 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
937 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000938 return *desc;
939 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000940 }
941 }
942
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000943 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000944 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000945
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000946 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000947 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000948 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000949
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000950 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000951 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000952 }
953
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000954 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
955 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000956
957 bool is_js_accessor = (result.type() == CALLBACKS) &&
958 (result.GetCallbackObject()->IsFixedArray());
959
960 if (is_js_accessor) {
961 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000962 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000963
964 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
965 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
966 elms->set(GETTER_INDEX, structure->get(0));
967 }
968 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
969 elms->set(SETTER_INDEX, structure->get(1));
970 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000971 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000972 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
973 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000974
975 PropertyAttributes attrs;
976 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000977 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000978 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
979 if (!maybe_value->ToObject(&value)) return maybe_value;
980 }
981 elms->set(VALUE_INDEX, value);
982 }
983
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000984 return *desc;
985}
986
987
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000988RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000989 ASSERT(args.length() == 1);
990 CONVERT_CHECKED(JSObject, obj, args[0]);
991 return obj->PreventExtensions();
992}
993
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000994
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000995RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000996 ASSERT(args.length() == 1);
997 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000998 if (obj->IsJSGlobalProxy()) {
999 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001000 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001001 ASSERT(proto->IsJSGlobalObject());
1002 obj = JSObject::cast(proto);
1003 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001004 return obj->map()->is_extensible() ? isolate->heap()->true_value()
1005 : isolate->heap()->false_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001006}
1007
1008
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001009RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001010 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001011 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001012 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
1013 CONVERT_ARG_CHECKED(String, pattern, 1);
1014 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001015 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1016 if (result.is_null()) return Failure::Exception();
1017 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001018}
1019
1020
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001021RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001022 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001023 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001024 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001025 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001026}
1027
1028
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001029RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001030 ASSERT(args.length() == 1);
1031 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001032 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001033 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001034}
1035
1036
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001037RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001038 ASSERT(args.length() == 2);
1039 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001040 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001041 int index = field->value();
1042 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1043 InstanceType type = templ->map()->instance_type();
1044 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1045 type == OBJECT_TEMPLATE_INFO_TYPE);
1046 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001047 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001048 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1049 } else {
1050 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1051 }
1052 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001053}
1054
1055
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001056RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
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 bool needs_access_checks = old_map->is_access_check_needed();
1061 if (needs_access_checks) {
1062 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001063 Object* new_map;
1064 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1065 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1066 }
ager@chromium.org32912102009-01-16 10:38:43 +00001067
1068 Map::cast(new_map)->set_is_access_check_needed(false);
1069 object->set_map(Map::cast(new_map));
1070 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001071 return needs_access_checks ? isolate->heap()->true_value()
1072 : isolate->heap()->false_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001073}
1074
1075
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001076RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001077 ASSERT(args.length() == 1);
1078 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001079 Map* old_map = object->map();
1080 if (!old_map->is_access_check_needed()) {
1081 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001082 Object* new_map;
1083 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1084 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1085 }
ager@chromium.org32912102009-01-16 10:38:43 +00001086
1087 Map::cast(new_map)->set_is_access_check_needed(true);
1088 object->set_map(Map::cast(new_map));
1089 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001090 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001091}
1092
1093
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001094static Failure* ThrowRedeclarationError(Isolate* isolate,
1095 const char* type,
1096 Handle<String> name) {
1097 HandleScope scope(isolate);
1098 Handle<Object> type_handle =
1099 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001100 Handle<Object> args[2] = { type_handle, name };
1101 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001102 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1103 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001104}
1105
1106
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001107RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001108 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001109 HandleScope scope(isolate);
1110 Handle<GlobalObject> global = Handle<GlobalObject>(
1111 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001112
ager@chromium.org3811b432009-10-28 14:53:37 +00001113 Handle<Context> context = args.at<Context>(0);
1114 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001115 bool is_eval = args.smi_at(2) == 1;
1116 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(3));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001117 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001118
1119 // Compute the property attributes. According to ECMA-262, section
1120 // 13, page 71, the property must be read-only and
1121 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1122 // property as read-only, so we don't either.
1123 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1124
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001125 // Traverse the name/value pairs and set the properties.
1126 int length = pairs->length();
1127 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001128 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001129 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001130 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001131
1132 // We have to declare a global const property. To capture we only
1133 // assign to it when evaluating the assignment for "const x =
1134 // <expr>" the initial value is the hole.
1135 bool is_const_property = value->IsTheHole();
1136
1137 if (value->IsUndefined() || is_const_property) {
1138 // Lookup the property in the global object, and don't set the
1139 // value of the variable if the property is already there.
1140 LookupResult lookup;
1141 global->Lookup(*name, &lookup);
1142 if (lookup.IsProperty()) {
1143 // Determine if the property is local by comparing the holder
1144 // against the global object. The information will be used to
1145 // avoid throwing re-declaration errors when declaring
1146 // variables or constants that exist in the prototype chain.
1147 bool is_local = (*global == lookup.holder());
1148 // Get the property attributes and determine if the property is
1149 // read-only.
1150 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1151 bool is_read_only = (attributes & READ_ONLY) != 0;
1152 if (lookup.type() == INTERCEPTOR) {
1153 // If the interceptor says the property is there, we
1154 // just return undefined without overwriting the property.
1155 // Otherwise, we continue to setting the property.
1156 if (attributes != ABSENT) {
1157 // Check if the existing property conflicts with regards to const.
1158 if (is_local && (is_read_only || is_const_property)) {
1159 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001160 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001161 };
1162 // The property already exists without conflicting: Go to
1163 // the next declaration.
1164 continue;
1165 }
1166 // Fall-through and introduce the absent property by using
1167 // SetProperty.
1168 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001169 // For const properties, we treat a callback with this name
1170 // even in the prototype as a conflicting declaration.
1171 if (is_const_property && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001172 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001173 }
1174 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001175 if (is_local && (is_read_only || is_const_property)) {
1176 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001177 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001178 }
1179 // The property already exists without conflicting: Go to
1180 // the next declaration.
1181 continue;
1182 }
1183 }
1184 } else {
1185 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001186 Handle<SharedFunctionInfo> shared =
1187 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001188 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001189 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1190 context,
1191 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001192 value = function;
1193 }
1194
1195 LookupResult lookup;
1196 global->LocalLookup(*name, &lookup);
1197
1198 PropertyAttributes attributes = is_const_property
1199 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1200 : base;
1201
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001202 // There's a local property that we need to overwrite because
1203 // we're either declaring a function or there's an interceptor
1204 // that claims the property is absent.
1205 //
1206 // Check for conflicting re-declarations. We cannot have
1207 // conflicting types in case of intercepted properties because
1208 // they are absent.
1209 if (lookup.IsProperty() &&
1210 (lookup.type() != INTERCEPTOR) &&
1211 (lookup.IsReadOnly() || is_const_property)) {
1212 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001213 return ThrowRedeclarationError(isolate, type, name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001214 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001215
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001216 // Safari does not allow the invocation of callback setters for
1217 // function declarations. To mimic this behavior, we do not allow
1218 // the invocation of setters for function values. This makes a
1219 // difference for global functions with the same names as event
1220 // handlers such as "function onload() {}". Firefox does call the
1221 // onload setter in those case and Safari does not. We follow
1222 // Safari for compatibility.
1223 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001224 // Do not change DONT_DELETE to false from true.
1225 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
1226 attributes = static_cast<PropertyAttributes>(
1227 attributes | (lookup.GetAttributes() & DONT_DELETE));
1228 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001229 RETURN_IF_EMPTY_HANDLE(isolate,
1230 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001231 name,
1232 value,
1233 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001234 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001235 RETURN_IF_EMPTY_HANDLE(isolate,
1236 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001237 name,
1238 value,
1239 attributes,
1240 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001241 }
1242 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001243
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001244 ASSERT(!isolate->has_pending_exception());
1245 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001246}
1247
1248
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001249RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001250 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001251 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001252
ager@chromium.org7c537e22008-10-16 08:43:32 +00001253 CONVERT_ARG_CHECKED(Context, context, 0);
1254 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001255 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001256 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001257 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001258
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001259 // Declarations are always done in a function or global context.
1260 context = Handle<Context>(context->declaration_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001261
1262 int index;
1263 PropertyAttributes attributes;
1264 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001265 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001266 context->Lookup(name, flags, &index, &attributes);
1267
1268 if (attributes != ABSENT) {
1269 // The name was declared before; check for conflicting
1270 // re-declarations: This is similar to the code in parser.cc in
1271 // the AstBuildingParser::Declare function.
1272 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1273 // Functions are not read-only.
1274 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1275 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001276 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001277 }
1278
1279 // Initialize it if necessary.
1280 if (*initial_value != NULL) {
1281 if (index >= 0) {
1282 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001283 // the function context or the arguments object.
1284 if (holder->IsContext()) {
1285 ASSERT(holder.is_identical_to(context));
1286 if (((attributes & READ_ONLY) == 0) ||
1287 context->get(index)->IsTheHole()) {
1288 context->set(index, *initial_value);
1289 }
1290 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001291 // The holder is an arguments object.
1292 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001293 Handle<Object> result = SetElement(arguments, index, initial_value,
1294 kNonStrictMode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001295 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001296 }
1297 } else {
1298 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001299 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001300 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001301 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001302 SetProperty(context_ext, name, initial_value,
1303 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001304 }
1305 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001306
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001307 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001308 // The property is not in the function context. It needs to be
1309 // "declared" in the function context's extension context, or in the
1310 // global context.
1311 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001312 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001313 // The function context's extension context exists - use it.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001314 context_ext = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001315 } else {
1316 // The function context's extension context does not exists - allocate
1317 // it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001318 context_ext = isolate->factory()->NewJSObject(
1319 isolate->context_extension_function());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001320 // And store it in the extension slot.
1321 context->set_extension(*context_ext);
1322 }
1323 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001324
ager@chromium.org7c537e22008-10-16 08:43:32 +00001325 // Declare the property by setting it to the initial value if provided,
1326 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1327 // constant declarations).
1328 ASSERT(!context_ext->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001329 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001330 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001331 // Declaring a const context slot is a conflicting declaration if
1332 // there is a callback with that name in a prototype. It is
1333 // allowed to introduce const variables in
1334 // JSContextExtensionObjects. They are treated specially in
1335 // SetProperty and no setters are invoked for those since they are
1336 // not real JSObjects.
1337 if (initial_value->IsTheHole() &&
1338 !context_ext->IsJSContextExtensionObject()) {
1339 LookupResult lookup;
1340 context_ext->Lookup(*name, &lookup);
1341 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001342 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001343 }
1344 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001345 RETURN_IF_EMPTY_HANDLE(isolate,
1346 SetProperty(context_ext, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001347 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001348 }
1349
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001350 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001351}
1352
1353
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001354RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001355 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001356 // args[0] == name
1357 // args[1] == strict_mode
1358 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001359
1360 // Determine if we need to assign to the variable if it already
1361 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001362 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1363 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001364
1365 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001366 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001367 RUNTIME_ASSERT(args[1]->IsSmi());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001368 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001369 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001370
1371 // According to ECMA-262, section 12.2, page 62, the property must
1372 // not be deletable.
1373 PropertyAttributes attributes = DONT_DELETE;
1374
1375 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001376 // there, there is a property with this name in the prototype chain.
1377 // We follow Safari and Firefox behavior and only set the property
1378 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001379 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001380 // Note that objects can have hidden prototypes, so we need to traverse
1381 // the whole chain of hidden prototypes to do a 'local' lookup.
1382 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001383 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001384 while (true) {
1385 real_holder->LocalLookup(*name, &lookup);
1386 if (lookup.IsProperty()) {
1387 // Determine if this is a redeclaration of something read-only.
1388 if (lookup.IsReadOnly()) {
1389 // If we found readonly property on one of hidden prototypes,
1390 // just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001391 if (real_holder != isolate->context()->global()) break;
1392 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001393 }
1394
1395 // Determine if this is a redeclaration of an intercepted read-only
1396 // property and figure out if the property exists at all.
1397 bool found = true;
1398 PropertyType type = lookup.type();
1399 if (type == INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001400 HandleScope handle_scope(isolate);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001401 Handle<JSObject> holder(real_holder);
1402 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1403 real_holder = *holder;
1404 if (intercepted == ABSENT) {
1405 // The interceptor claims the property isn't there. We need to
1406 // make sure to introduce it.
1407 found = false;
1408 } else if ((intercepted & READ_ONLY) != 0) {
1409 // The property is present, but read-only. Since we're trying to
1410 // overwrite it with a variable declaration we must throw a
1411 // re-declaration error. However if we found readonly property
1412 // on one of hidden prototypes, just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001413 if (real_holder != isolate->context()->global()) break;
1414 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001415 }
1416 }
1417
1418 if (found && !assign) {
1419 // The global property is there and we're not assigning any value
1420 // to it. Just return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001421 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001422 }
1423
1424 // Assign the value (or undefined) to the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001425 Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001426 return real_holder->SetProperty(
1427 &lookup, *name, value, attributes, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001428 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001429
1430 Object* proto = real_holder->GetPrototype();
1431 if (!proto->IsJSObject())
1432 break;
1433
1434 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1435 break;
1436
1437 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001438 }
1439
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001440 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001441 if (assign) {
1442 return global->SetProperty(*name, args[2], attributes, strict_mode);
1443 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001444 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001445}
1446
1447
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001448RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001449 // All constants are declared with an initial value. The name
1450 // of the constant is the first argument and the initial value
1451 // is the second.
1452 RUNTIME_ASSERT(args.length() == 2);
1453 CONVERT_ARG_CHECKED(String, name, 0);
1454 Handle<Object> value = args.at<Object>(1);
1455
1456 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001457 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001458
1459 // According to ECMA-262, section 12.2, page 62, the property must
1460 // not be deletable. Since it's a const, it must be READ_ONLY too.
1461 PropertyAttributes attributes =
1462 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1463
1464 // Lookup the property locally in the global object. If it isn't
1465 // there, we add the property and take special precautions to always
1466 // add it as a local property even in case of callbacks in the
1467 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001468 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001469 LookupResult lookup;
1470 global->LocalLookup(*name, &lookup);
1471 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001472 return global->SetLocalPropertyIgnoreAttributes(*name,
1473 *value,
1474 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001475 }
1476
1477 // Determine if this is a redeclaration of something not
1478 // read-only. In case the result is hidden behind an interceptor we
1479 // need to ask it for the property attributes.
1480 if (!lookup.IsReadOnly()) {
1481 if (lookup.type() != INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001482 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001483 }
1484
1485 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1486
1487 // Throw re-declaration error if the intercepted property is present
1488 // but not read-only.
1489 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001490 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001491 }
1492
1493 // Restore global object from context (in case of GC) and continue
1494 // with setting the value because the property is either absent or
1495 // read-only. We also have to do redo the lookup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001496 HandleScope handle_scope(isolate);
1497 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001498
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001499 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001500 // property through an interceptor and only do it if it's
1501 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001502 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001503 RETURN_IF_EMPTY_HANDLE(isolate,
1504 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001505 name,
1506 value,
1507 attributes,
1508 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001509 return *value;
1510 }
1511
1512 // Set the value, but only we're assigning the initial value to a
1513 // constant. For now, we determine this by checking if the
1514 // current value is the hole.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001515 // Strict mode handling not needed (const disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001516 PropertyType type = lookup.type();
1517 if (type == FIELD) {
1518 FixedArray* properties = global->properties();
1519 int index = lookup.GetFieldIndex();
1520 if (properties->get(index)->IsTheHole()) {
1521 properties->set(index, *value);
1522 }
1523 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001524 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1525 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001526 }
1527 } else {
1528 // Ignore re-initialization of constants that have already been
1529 // assigned a function value.
1530 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1531 }
1532
1533 // Use the set value as the result of the operation.
1534 return *value;
1535}
1536
1537
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001538RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001539 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001540 ASSERT(args.length() == 3);
1541
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001542 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001543 ASSERT(!value->IsTheHole());
1544 CONVERT_ARG_CHECKED(Context, context, 1);
1545 Handle<String> name(String::cast(args[2]));
1546
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001547 // Initializations are always done in a function or global context.
1548 context = Handle<Context>(context->declaration_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001549
1550 int index;
1551 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001552 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001553 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001554 context->Lookup(name, flags, &index, &attributes);
1555
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001556 // In most situations, the property introduced by the const
1557 // declaration should be present in the context extension object.
1558 // However, because declaration and initialization are separate, the
1559 // property might have been deleted (if it was introduced by eval)
1560 // before we reach the initialization point.
1561 //
1562 // Example:
1563 //
1564 // function f() { eval("delete x; const x;"); }
1565 //
1566 // In that case, the initialization behaves like a normal assignment
1567 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001568 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001569 if (holder->IsContext()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001570 // Property was found in a context. Perform the assignment if we
1571 // found some non-constant or an uninitialized constant.
1572 Handle<Context> context = Handle<Context>::cast(holder);
1573 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1574 context->set(index, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001575 }
1576 } else {
1577 // The holder is an arguments object.
1578 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001579 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001580 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001581 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001582 SetElement(arguments, index, value, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001583 }
1584 return *value;
1585 }
1586
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001587 // The property could not be found, we introduce it in the global
1588 // context.
1589 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001590 Handle<JSObject> global = Handle<JSObject>(
1591 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001592 // Strict mode not needed (const disallowed in strict mode).
1593 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001594 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001595 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001596 return *value;
1597 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001598
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001599 // The property was present in a context extension object.
1600 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001601
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001602 if (*context_ext == context->extension()) {
1603 // This is the property that was introduced by the const
1604 // declaration. Set it if it hasn't been set before. NOTE: We
1605 // cannot use GetProperty() to get the current value as it
1606 // 'unholes' the value.
1607 LookupResult lookup;
1608 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1609 ASSERT(lookup.IsProperty()); // the property was declared
1610 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1611
1612 PropertyType type = lookup.type();
1613 if (type == FIELD) {
1614 FixedArray* properties = context_ext->properties();
1615 int index = lookup.GetFieldIndex();
1616 if (properties->get(index)->IsTheHole()) {
1617 properties->set(index, *value);
1618 }
1619 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001620 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1621 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001622 }
1623 } else {
1624 // We should not reach here. Any real, named property should be
1625 // either a field or a dictionary slot.
1626 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001627 }
1628 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001629 // The property was found in a different context extension object.
1630 // Set it if it is not a read-only property.
1631 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001632 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001633 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001634 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001635 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001636 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001637 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001638
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001639 return *value;
1640}
1641
1642
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001643RUNTIME_FUNCTION(MaybeObject*,
1644 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001645 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001646 ASSERT(args.length() == 2);
1647 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001648 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001649 if (object->HasFastProperties()) {
1650 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1651 }
1652 return *object;
1653}
1654
1655
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001656RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001657 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001658 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001659 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1660 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001661 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001662 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001663 CONVERT_SMI_ARG_CHECKED(index, 2);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001664 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001665 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001666 RUNTIME_ASSERT(index >= 0);
1667 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001668 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001669 Handle<Object> result = RegExpImpl::Exec(regexp,
1670 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001671 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001672 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001673 if (result.is_null()) return Failure::Exception();
1674 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001675}
1676
1677
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001678RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001679 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001680 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001681 if (elements_count < 0 ||
1682 elements_count > FixedArray::kMaxLength ||
1683 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001684 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001685 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001686 Object* new_object;
1687 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001688 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001689 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1690 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001691 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001692 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1693 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001694 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1695 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001696 {
1697 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001698 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001699 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001700 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001701 }
1702 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001703 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001704 array->set_elements(elements);
1705 array->set_length(Smi::FromInt(elements_count));
1706 // Write in-object properties after the length of the array.
1707 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1708 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1709 return array;
1710}
1711
1712
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001713RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001714 AssertNoAllocation no_alloc;
1715 ASSERT(args.length() == 5);
1716 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1717 CONVERT_CHECKED(String, source, args[1]);
1718
1719 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001720 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001721
1722 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001723 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001724
1725 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001726 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001727
1728 Map* map = regexp->map();
1729 Object* constructor = map->constructor();
1730 if (constructor->IsJSFunction() &&
1731 JSFunction::cast(constructor)->initial_map() == map) {
1732 // If we still have the original map, set in-object properties directly.
1733 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1734 // TODO(lrn): Consider skipping write barrier on booleans as well.
1735 // Both true and false should be in oldspace at all times.
1736 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1737 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1738 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1739 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1740 Smi::FromInt(0),
1741 SKIP_WRITE_BARRIER);
1742 return regexp;
1743 }
1744
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001745 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001746 PropertyAttributes final =
1747 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1748 PropertyAttributes writable =
1749 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001750 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001751 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001752 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001753 source,
1754 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001755 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001756 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001757 global,
1758 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001759 ASSERT(!result->IsFailure());
1760 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001761 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001762 ignoreCase,
1763 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001764 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001765 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001766 multiline,
1767 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001768 ASSERT(!result->IsFailure());
1769 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001770 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001771 Smi::FromInt(0),
1772 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001773 ASSERT(!result->IsFailure());
1774 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001775 return regexp;
1776}
1777
1778
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001779RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001780 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001781 ASSERT(args.length() == 1);
1782 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1783 // This is necessary to enable fast checks for absence of elements
1784 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001785 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001786 return Smi::FromInt(0);
1787}
1788
1789
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001790static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1791 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001792 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001793 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001794 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1795 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1796 Handle<JSFunction> optimized =
1797 isolate->factory()->NewFunction(key,
1798 JS_OBJECT_TYPE,
1799 JSObject::kHeaderSize,
1800 code,
1801 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001802 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001803 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001804 return optimized;
1805}
1806
1807
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001808RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001809 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001810 ASSERT(args.length() == 1);
1811 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1812
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001813 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1814 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1815 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1816 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1817 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1818 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1819 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001820
1821 return *holder;
1822}
1823
1824
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001825RUNTIME_FUNCTION(MaybeObject*, Runtime_GetGlobalReceiver) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001826 // Returns a real global receiver, not one of builtins object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001827 Context* global_context =
1828 isolate->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001829 return global_context->global()->global_receiver();
1830}
1831
1832
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001833RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001834 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001835 ASSERT(args.length() == 4);
1836 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001837 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001838 Handle<String> pattern = args.at<String>(2);
1839 Handle<String> flags = args.at<String>(3);
1840
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001841 // Get the RegExp function from the context in the literals array.
1842 // This is the RegExp function from the context in which the
1843 // function was created. We do not use the RegExp function from the
1844 // current global context because this might be the RegExp function
1845 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001846 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001847 Handle<JSFunction>(
1848 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001849 // Compute the regular expression literal.
1850 bool has_pending_exception;
1851 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001852 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1853 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001854 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001855 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001856 return Failure::Exception();
1857 }
1858 literals->set(index, *regexp);
1859 return *regexp;
1860}
1861
1862
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001863RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001864 NoHandleAllocation ha;
1865 ASSERT(args.length() == 1);
1866
1867 CONVERT_CHECKED(JSFunction, f, args[0]);
1868 return f->shared()->name();
1869}
1870
1871
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001872RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001873 NoHandleAllocation ha;
1874 ASSERT(args.length() == 2);
1875
1876 CONVERT_CHECKED(JSFunction, f, args[0]);
1877 CONVERT_CHECKED(String, name, args[1]);
1878 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001879 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001880}
1881
1882
whesse@chromium.org7b260152011-06-20 15:33:18 +00001883RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetBound) {
1884 HandleScope scope(isolate);
1885 ASSERT(args.length() == 1);
1886
1887 CONVERT_CHECKED(JSFunction, fun, args[0]);
1888 fun->shared()->set_bound(true);
1889 return isolate->heap()->undefined_value();
1890}
1891
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001892RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001893 NoHandleAllocation ha;
1894 ASSERT(args.length() == 1);
1895
1896 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001897 Object* obj = f->RemovePrototype();
1898 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001899
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001900 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001901}
1902
1903
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001904RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001905 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001906 ASSERT(args.length() == 1);
1907
1908 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001909 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1910 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001911
1912 return *GetScriptWrapper(Handle<Script>::cast(script));
1913}
1914
1915
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001916RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001917 NoHandleAllocation ha;
1918 ASSERT(args.length() == 1);
1919
1920 CONVERT_CHECKED(JSFunction, f, args[0]);
1921 return f->shared()->GetSourceCode();
1922}
1923
1924
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001925RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001926 NoHandleAllocation ha;
1927 ASSERT(args.length() == 1);
1928
1929 CONVERT_CHECKED(JSFunction, fun, args[0]);
1930 int pos = fun->shared()->start_position();
1931 return Smi::FromInt(pos);
1932}
1933
1934
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001935RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001936 ASSERT(args.length() == 2);
1937
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001938 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001939 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1940
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001941 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1942
1943 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001944 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001945}
1946
1947
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001948RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001949 NoHandleAllocation ha;
1950 ASSERT(args.length() == 2);
1951
1952 CONVERT_CHECKED(JSFunction, fun, args[0]);
1953 CONVERT_CHECKED(String, name, args[1]);
1954 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001955 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001956}
1957
1958
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001959RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001960 NoHandleAllocation ha;
1961 ASSERT(args.length() == 2);
1962
1963 CONVERT_CHECKED(JSFunction, fun, args[0]);
1964 CONVERT_CHECKED(Smi, length, args[1]);
1965 fun->shared()->set_length(length->value());
1966 return length;
1967}
1968
1969
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001970RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001971 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001972 ASSERT(args.length() == 2);
1973
1974 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001975 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001976 Object* obj;
1977 { MaybeObject* maybe_obj =
1978 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1979 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1980 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001981 return args[0]; // return TOS
1982}
1983
1984
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001985RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
1986 NoHandleAllocation ha;
1987 RUNTIME_ASSERT(args.length() == 1);
1988 CONVERT_CHECKED(JSFunction, function, args[0]);
1989
1990 MaybeObject* maybe_name =
1991 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
1992 String* name;
1993 if (!maybe_name->To(&name)) return maybe_name;
1994
1995 if (function->HasFastProperties()) {
1996 // Construct a new field descriptor with updated attributes.
1997 DescriptorArray* instance_desc = function->map()->instance_descriptors();
1998 int index = instance_desc->Search(name);
1999 ASSERT(index != DescriptorArray::kNotFound);
2000 PropertyDetails details(instance_desc->GetDetails(index));
2001 CallbacksDescriptor new_desc(name,
2002 instance_desc->GetValue(index),
2003 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2004 details.index());
2005 // Construct a new field descriptors array containing the new descriptor.
2006 Object* descriptors_unchecked;
2007 { MaybeObject* maybe_descriptors_unchecked =
2008 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2009 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2010 return maybe_descriptors_unchecked;
2011 }
2012 }
2013 DescriptorArray* new_descriptors =
2014 DescriptorArray::cast(descriptors_unchecked);
2015 // Create a new map featuring the new field descriptors array.
2016 Object* map_unchecked;
2017 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2018 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2019 return maybe_map_unchecked;
2020 }
2021 }
2022 Map* new_map = Map::cast(map_unchecked);
2023 new_map->set_instance_descriptors(new_descriptors);
2024 function->set_map(new_map);
2025 } else { // Dictionary properties.
2026 // Directly manipulate the property details.
2027 int entry = function->property_dictionary()->FindEntry(name);
2028 ASSERT(entry != StringDictionary::kNotFound);
2029 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2030 PropertyDetails new_details(
2031 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2032 details.type(),
2033 details.index());
2034 function->property_dictionary()->DetailsAtPut(entry, new_details);
2035 }
2036 return function;
2037}
2038
2039
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002040RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002041 NoHandleAllocation ha;
2042 ASSERT(args.length() == 1);
2043
2044 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002045 return f->shared()->IsApiFunction() ? isolate->heap()->true_value()
2046 : isolate->heap()->false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002047}
2048
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002049
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002050RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002051 NoHandleAllocation ha;
2052 ASSERT(args.length() == 1);
2053
2054 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002055 return f->IsBuiltin() ? isolate->heap()->true_value() :
2056 isolate->heap()->false_value();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002057}
2058
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002059
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002060RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002061 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002062 ASSERT(args.length() == 2);
2063
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002064 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002065 Handle<Object> code = args.at<Object>(1);
2066
2067 Handle<Context> context(target->context());
2068
2069 if (!code->IsNull()) {
2070 RUNTIME_ASSERT(code->IsJSFunction());
2071 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002072 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002073
2074 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002075 return Failure::Exception();
2076 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002077 // Since we don't store the source for this we should never
2078 // optimize this.
2079 shared->code()->set_optimizable(false);
2080
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002081 // Set the code, scope info, formal parameter count,
2082 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002083 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002084 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002085 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002086 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002087 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002088 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002089 // Set the source code of the target function to undefined.
2090 // SetCode is only used for built-in constructors like String,
2091 // Array, and Object, and some web code
2092 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002093 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002094 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002095 // Clear the optimization hints related to the compiled code as these are no
2096 // longer valid when the code is overwritten.
2097 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002098 context = Handle<Context>(fun->context());
2099
2100 // Make sure we get a fresh copy of the literal vector to avoid
2101 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002102 int number_of_literals = fun->NumberOfLiterals();
2103 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002104 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002105 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002106 // Insert the object, regexp and array functions in the literals
2107 // array prefix. These are the functions that will be used when
2108 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002109 literals->set(JSFunction::kLiteralGlobalContextIndex,
2110 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002111 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002112 // It's okay to skip the write barrier here because the literals
2113 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002114 target->set_literals(*literals, SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002115 target->set_next_function_link(isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002116 }
2117
2118 target->set_context(*context);
2119 return *target;
2120}
2121
2122
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002123RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002124 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002125 ASSERT(args.length() == 2);
2126 CONVERT_ARG_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002127 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002128 RUNTIME_ASSERT(num >= 0);
2129 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002130 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002131}
2132
2133
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002134MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2135 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002136 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002137 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002138 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002139 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002140 }
2141 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002142 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002143}
2144
2145
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002146RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002147 NoHandleAllocation ha;
2148 ASSERT(args.length() == 2);
2149
2150 CONVERT_CHECKED(String, subject, args[0]);
2151 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002152 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002153
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002154 uint32_t i = 0;
2155 if (index->IsSmi()) {
2156 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002157 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002158 i = value;
2159 } else {
2160 ASSERT(index->IsHeapNumber());
2161 double value = HeapNumber::cast(index)->value();
2162 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002163 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002164
2165 // Flatten the string. If someone wants to get a char at an index
2166 // in a cons string, it is likely that more indices will be
2167 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002168 Object* flat;
2169 { MaybeObject* maybe_flat = subject->TryFlatten();
2170 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2171 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002172 subject = String::cast(flat);
2173
2174 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002175 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002176 }
2177
2178 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002179}
2180
2181
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002182RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002183 NoHandleAllocation ha;
2184 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002185 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002186}
2187
lrn@chromium.org25156de2010-04-06 13:10:27 +00002188
2189class FixedArrayBuilder {
2190 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002191 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2192 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002193 length_(0) {
2194 // Require a non-zero initial size. Ensures that doubling the size to
2195 // extend the array will work.
2196 ASSERT(initial_capacity > 0);
2197 }
2198
2199 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2200 : array_(backing_store),
2201 length_(0) {
2202 // Require a non-zero initial size. Ensures that doubling the size to
2203 // extend the array will work.
2204 ASSERT(backing_store->length() > 0);
2205 }
2206
2207 bool HasCapacity(int elements) {
2208 int length = array_->length();
2209 int required_length = length_ + elements;
2210 return (length >= required_length);
2211 }
2212
2213 void EnsureCapacity(int elements) {
2214 int length = array_->length();
2215 int required_length = length_ + elements;
2216 if (length < required_length) {
2217 int new_length = length;
2218 do {
2219 new_length *= 2;
2220 } while (new_length < required_length);
2221 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002222 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002223 array_->CopyTo(0, *extended_array, 0, length_);
2224 array_ = extended_array;
2225 }
2226 }
2227
2228 void Add(Object* value) {
2229 ASSERT(length_ < capacity());
2230 array_->set(length_, value);
2231 length_++;
2232 }
2233
2234 void Add(Smi* value) {
2235 ASSERT(length_ < capacity());
2236 array_->set(length_, value);
2237 length_++;
2238 }
2239
2240 Handle<FixedArray> array() {
2241 return array_;
2242 }
2243
2244 int length() {
2245 return length_;
2246 }
2247
2248 int capacity() {
2249 return array_->length();
2250 }
2251
2252 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002253 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002254 result_array->set_length(Smi::FromInt(length_));
2255 return result_array;
2256 }
2257
2258 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2259 target_array->set_elements(*array_);
2260 target_array->set_length(Smi::FromInt(length_));
2261 return target_array;
2262 }
2263
2264 private:
2265 Handle<FixedArray> array_;
2266 int length_;
2267};
2268
2269
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002270// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002271const int kStringBuilderConcatHelperLengthBits = 11;
2272const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002273
2274template <typename schar>
2275static inline void StringBuilderConcatHelper(String*,
2276 schar*,
2277 FixedArray*,
2278 int);
2279
lrn@chromium.org25156de2010-04-06 13:10:27 +00002280typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2281 StringBuilderSubstringLength;
2282typedef BitField<int,
2283 kStringBuilderConcatHelperLengthBits,
2284 kStringBuilderConcatHelperPositionBits>
2285 StringBuilderSubstringPosition;
2286
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002287
2288class ReplacementStringBuilder {
2289 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002290 ReplacementStringBuilder(Heap* heap,
2291 Handle<String> subject,
2292 int estimated_part_count)
2293 : heap_(heap),
2294 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002295 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002296 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002297 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002298 // Require a non-zero initial size. Ensures that doubling the size to
2299 // extend the array will work.
2300 ASSERT(estimated_part_count > 0);
2301 }
2302
lrn@chromium.org25156de2010-04-06 13:10:27 +00002303 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2304 int from,
2305 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002306 ASSERT(from >= 0);
2307 int length = to - from;
2308 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002309 if (StringBuilderSubstringLength::is_valid(length) &&
2310 StringBuilderSubstringPosition::is_valid(from)) {
2311 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2312 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002313 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002314 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002315 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002316 builder->Add(Smi::FromInt(-length));
2317 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002318 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002319 }
2320
2321
2322 void EnsureCapacity(int elements) {
2323 array_builder_.EnsureCapacity(elements);
2324 }
2325
2326
2327 void AddSubjectSlice(int from, int to) {
2328 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002329 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002330 }
2331
2332
2333 void AddString(Handle<String> string) {
2334 int length = string->length();
2335 ASSERT(length > 0);
2336 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002337 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002338 is_ascii_ = false;
2339 }
2340 IncrementCharacterCount(length);
2341 }
2342
2343
2344 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002345 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002346 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002347 }
2348
2349 Handle<String> joined_string;
2350 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002351 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002352 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002353 char* char_buffer = seq->GetChars();
2354 StringBuilderConcatHelper(*subject_,
2355 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002356 *array_builder_.array(),
2357 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002358 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002359 } else {
2360 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002361 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002362 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002363 uc16* char_buffer = seq->GetChars();
2364 StringBuilderConcatHelper(*subject_,
2365 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002366 *array_builder_.array(),
2367 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002368 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002369 }
2370 return joined_string;
2371 }
2372
2373
2374 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002375 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002376 V8::FatalProcessOutOfMemory("String.replace result too large.");
2377 }
2378 character_count_ += by;
2379 }
2380
lrn@chromium.org25156de2010-04-06 13:10:27 +00002381 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002382 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002383 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002384
lrn@chromium.org25156de2010-04-06 13:10:27 +00002385 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002386 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2387 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002388 }
2389
2390
ager@chromium.org04921a82011-06-27 13:21:41 +00002391 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2392 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002393 }
2394
2395
2396 void AddElement(Object* element) {
2397 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002398 ASSERT(array_builder_.capacity() > array_builder_.length());
2399 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002400 }
2401
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002402 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002403 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002404 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002405 int character_count_;
2406 bool is_ascii_;
2407};
2408
2409
2410class CompiledReplacement {
2411 public:
2412 CompiledReplacement()
2413 : parts_(1), replacement_substrings_(0) {}
2414
2415 void Compile(Handle<String> replacement,
2416 int capture_count,
2417 int subject_length);
2418
2419 void Apply(ReplacementStringBuilder* builder,
2420 int match_from,
2421 int match_to,
2422 Handle<JSArray> last_match_info);
2423
2424 // Number of distinct parts of the replacement pattern.
2425 int parts() {
2426 return parts_.length();
2427 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002428
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002429 private:
2430 enum PartType {
2431 SUBJECT_PREFIX = 1,
2432 SUBJECT_SUFFIX,
2433 SUBJECT_CAPTURE,
2434 REPLACEMENT_SUBSTRING,
2435 REPLACEMENT_STRING,
2436
2437 NUMBER_OF_PART_TYPES
2438 };
2439
2440 struct ReplacementPart {
2441 static inline ReplacementPart SubjectMatch() {
2442 return ReplacementPart(SUBJECT_CAPTURE, 0);
2443 }
2444 static inline ReplacementPart SubjectCapture(int capture_index) {
2445 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2446 }
2447 static inline ReplacementPart SubjectPrefix() {
2448 return ReplacementPart(SUBJECT_PREFIX, 0);
2449 }
2450 static inline ReplacementPart SubjectSuffix(int subject_length) {
2451 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2452 }
2453 static inline ReplacementPart ReplacementString() {
2454 return ReplacementPart(REPLACEMENT_STRING, 0);
2455 }
2456 static inline ReplacementPart ReplacementSubString(int from, int to) {
2457 ASSERT(from >= 0);
2458 ASSERT(to > from);
2459 return ReplacementPart(-from, to);
2460 }
2461
2462 // If tag <= 0 then it is the negation of a start index of a substring of
2463 // the replacement pattern, otherwise it's a value from PartType.
2464 ReplacementPart(int tag, int data)
2465 : tag(tag), data(data) {
2466 // Must be non-positive or a PartType value.
2467 ASSERT(tag < NUMBER_OF_PART_TYPES);
2468 }
2469 // Either a value of PartType or a non-positive number that is
2470 // the negation of an index into the replacement string.
2471 int tag;
2472 // The data value's interpretation depends on the value of tag:
2473 // tag == SUBJECT_PREFIX ||
2474 // tag == SUBJECT_SUFFIX: data is unused.
2475 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2476 // tag == REPLACEMENT_SUBSTRING ||
2477 // tag == REPLACEMENT_STRING: data is index into array of substrings
2478 // of the replacement string.
2479 // tag <= 0: Temporary representation of the substring of the replacement
2480 // string ranging over -tag .. data.
2481 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2482 // substring objects.
2483 int data;
2484 };
2485
2486 template<typename Char>
2487 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2488 Vector<Char> characters,
2489 int capture_count,
2490 int subject_length) {
2491 int length = characters.length();
2492 int last = 0;
2493 for (int i = 0; i < length; i++) {
2494 Char c = characters[i];
2495 if (c == '$') {
2496 int next_index = i + 1;
2497 if (next_index == length) { // No next character!
2498 break;
2499 }
2500 Char c2 = characters[next_index];
2501 switch (c2) {
2502 case '$':
2503 if (i > last) {
2504 // There is a substring before. Include the first "$".
2505 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2506 last = next_index + 1; // Continue after the second "$".
2507 } else {
2508 // Let the next substring start with the second "$".
2509 last = next_index;
2510 }
2511 i = next_index;
2512 break;
2513 case '`':
2514 if (i > last) {
2515 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2516 }
2517 parts->Add(ReplacementPart::SubjectPrefix());
2518 i = next_index;
2519 last = i + 1;
2520 break;
2521 case '\'':
2522 if (i > last) {
2523 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2524 }
2525 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2526 i = next_index;
2527 last = i + 1;
2528 break;
2529 case '&':
2530 if (i > last) {
2531 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2532 }
2533 parts->Add(ReplacementPart::SubjectMatch());
2534 i = next_index;
2535 last = i + 1;
2536 break;
2537 case '0':
2538 case '1':
2539 case '2':
2540 case '3':
2541 case '4':
2542 case '5':
2543 case '6':
2544 case '7':
2545 case '8':
2546 case '9': {
2547 int capture_ref = c2 - '0';
2548 if (capture_ref > capture_count) {
2549 i = next_index;
2550 continue;
2551 }
2552 int second_digit_index = next_index + 1;
2553 if (second_digit_index < length) {
2554 // Peek ahead to see if we have two digits.
2555 Char c3 = characters[second_digit_index];
2556 if ('0' <= c3 && c3 <= '9') { // Double digits.
2557 int double_digit_ref = capture_ref * 10 + c3 - '0';
2558 if (double_digit_ref <= capture_count) {
2559 next_index = second_digit_index;
2560 capture_ref = double_digit_ref;
2561 }
2562 }
2563 }
2564 if (capture_ref > 0) {
2565 if (i > last) {
2566 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2567 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002568 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002569 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2570 last = next_index + 1;
2571 }
2572 i = next_index;
2573 break;
2574 }
2575 default:
2576 i = next_index;
2577 break;
2578 }
2579 }
2580 }
2581 if (length > last) {
2582 if (last == 0) {
2583 parts->Add(ReplacementPart::ReplacementString());
2584 } else {
2585 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2586 }
2587 }
2588 }
2589
2590 ZoneList<ReplacementPart> parts_;
2591 ZoneList<Handle<String> > replacement_substrings_;
2592};
2593
2594
2595void CompiledReplacement::Compile(Handle<String> replacement,
2596 int capture_count,
2597 int subject_length) {
2598 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002599 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002600 AssertNoAllocation no_alloc;
2601 ParseReplacementPattern(&parts_,
2602 replacement->ToAsciiVector(),
2603 capture_count,
2604 subject_length);
2605 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002606 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002607 AssertNoAllocation no_alloc;
2608
2609 ParseReplacementPattern(&parts_,
2610 replacement->ToUC16Vector(),
2611 capture_count,
2612 subject_length);
2613 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002614 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002615 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002616 int substring_index = 0;
2617 for (int i = 0, n = parts_.length(); i < n; i++) {
2618 int tag = parts_[i].tag;
2619 if (tag <= 0) { // A replacement string slice.
2620 int from = -tag;
2621 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002622 replacement_substrings_.Add(
2623 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002624 parts_[i].tag = REPLACEMENT_SUBSTRING;
2625 parts_[i].data = substring_index;
2626 substring_index++;
2627 } else if (tag == REPLACEMENT_STRING) {
2628 replacement_substrings_.Add(replacement);
2629 parts_[i].data = substring_index;
2630 substring_index++;
2631 }
2632 }
2633}
2634
2635
2636void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2637 int match_from,
2638 int match_to,
2639 Handle<JSArray> last_match_info) {
2640 for (int i = 0, n = parts_.length(); i < n; i++) {
2641 ReplacementPart part = parts_[i];
2642 switch (part.tag) {
2643 case SUBJECT_PREFIX:
2644 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2645 break;
2646 case SUBJECT_SUFFIX: {
2647 int subject_length = part.data;
2648 if (match_to < subject_length) {
2649 builder->AddSubjectSlice(match_to, subject_length);
2650 }
2651 break;
2652 }
2653 case SUBJECT_CAPTURE: {
2654 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002655 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002656 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2657 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2658 if (from >= 0 && to > from) {
2659 builder->AddSubjectSlice(from, to);
2660 }
2661 break;
2662 }
2663 case REPLACEMENT_SUBSTRING:
2664 case REPLACEMENT_STRING:
2665 builder->AddString(replacement_substrings_[part.data]);
2666 break;
2667 default:
2668 UNREACHABLE();
2669 }
2670 }
2671}
2672
2673
2674
lrn@chromium.org303ada72010-10-27 09:33:13 +00002675MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002676 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002677 String* subject,
2678 JSRegExp* regexp,
2679 String* replacement,
2680 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002681 ASSERT(subject->IsFlat());
2682 ASSERT(replacement->IsFlat());
2683
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002684 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002685
2686 int length = subject->length();
2687 Handle<String> subject_handle(subject);
2688 Handle<JSRegExp> regexp_handle(regexp);
2689 Handle<String> replacement_handle(replacement);
2690 Handle<JSArray> last_match_info_handle(last_match_info);
2691 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2692 subject_handle,
2693 0,
2694 last_match_info_handle);
2695 if (match.is_null()) {
2696 return Failure::Exception();
2697 }
2698 if (match->IsNull()) {
2699 return *subject_handle;
2700 }
2701
2702 int capture_count = regexp_handle->CaptureCount();
2703
2704 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002705 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002706 CompiledReplacement compiled_replacement;
2707 compiled_replacement.Compile(replacement_handle,
2708 capture_count,
2709 length);
2710
2711 bool is_global = regexp_handle->GetFlags().is_global();
2712
2713 // Guessing the number of parts that the final result string is built
2714 // from. Global regexps can match any number of times, so we guess
2715 // conservatively.
2716 int expected_parts =
2717 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002718 ReplacementStringBuilder builder(isolate->heap(),
2719 subject_handle,
2720 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002721
2722 // Index of end of last match.
2723 int prev = 0;
2724
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002725 // Number of parts added by compiled replacement plus preceeding
2726 // string and possibly suffix after last match. It is possible for
2727 // all components to use two elements when encoded as two smis.
2728 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002729 bool matched = true;
2730 do {
2731 ASSERT(last_match_info_handle->HasFastElements());
2732 // Increase the capacity of the builder before entering local handle-scope,
2733 // so its internal buffer can safely allocate a new handle if it grows.
2734 builder.EnsureCapacity(parts_added_per_loop);
2735
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002736 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002737 int start, end;
2738 {
2739 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002740 FixedArray* match_info_array =
2741 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002742
2743 ASSERT_EQ(capture_count * 2 + 2,
2744 RegExpImpl::GetLastCaptureCount(match_info_array));
2745 start = RegExpImpl::GetCapture(match_info_array, 0);
2746 end = RegExpImpl::GetCapture(match_info_array, 1);
2747 }
2748
2749 if (prev < start) {
2750 builder.AddSubjectSlice(prev, start);
2751 }
2752 compiled_replacement.Apply(&builder,
2753 start,
2754 end,
2755 last_match_info_handle);
2756 prev = end;
2757
2758 // Only continue checking for global regexps.
2759 if (!is_global) break;
2760
2761 // Continue from where the match ended, unless it was an empty match.
2762 int next = end;
2763 if (start == end) {
2764 next = end + 1;
2765 if (next > length) break;
2766 }
2767
2768 match = RegExpImpl::Exec(regexp_handle,
2769 subject_handle,
2770 next,
2771 last_match_info_handle);
2772 if (match.is_null()) {
2773 return Failure::Exception();
2774 }
2775 matched = !match->IsNull();
2776 } while (matched);
2777
2778 if (prev < length) {
2779 builder.AddSubjectSlice(prev, length);
2780 }
2781
2782 return *(builder.ToString());
2783}
2784
2785
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002786template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002787MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002788 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002789 String* subject,
2790 JSRegExp* regexp,
2791 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002792 ASSERT(subject->IsFlat());
2793
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002794 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002795
2796 Handle<String> subject_handle(subject);
2797 Handle<JSRegExp> regexp_handle(regexp);
2798 Handle<JSArray> last_match_info_handle(last_match_info);
2799 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2800 subject_handle,
2801 0,
2802 last_match_info_handle);
2803 if (match.is_null()) return Failure::Exception();
2804 if (match->IsNull()) return *subject_handle;
2805
2806 ASSERT(last_match_info_handle->HasFastElements());
2807
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002808 int start, end;
2809 {
2810 AssertNoAllocation match_info_array_is_not_in_a_handle;
2811 FixedArray* match_info_array =
2812 FixedArray::cast(last_match_info_handle->elements());
2813
2814 start = RegExpImpl::GetCapture(match_info_array, 0);
2815 end = RegExpImpl::GetCapture(match_info_array, 1);
2816 }
2817
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002818 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002819 int new_length = length - (end - start);
2820 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002821 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002822 }
2823 Handle<ResultSeqString> answer;
2824 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002825 answer = Handle<ResultSeqString>::cast(
2826 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002827 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002828 answer = Handle<ResultSeqString>::cast(
2829 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002830 }
2831
2832 // If the regexp isn't global, only match once.
2833 if (!regexp_handle->GetFlags().is_global()) {
2834 if (start > 0) {
2835 String::WriteToFlat(*subject_handle,
2836 answer->GetChars(),
2837 0,
2838 start);
2839 }
2840 if (end < length) {
2841 String::WriteToFlat(*subject_handle,
2842 answer->GetChars() + start,
2843 end,
2844 length);
2845 }
2846 return *answer;
2847 }
2848
2849 int prev = 0; // Index of end of last match.
2850 int next = 0; // Start of next search (prev unless last match was empty).
2851 int position = 0;
2852
2853 do {
2854 if (prev < start) {
2855 // Add substring subject[prev;start] to answer string.
2856 String::WriteToFlat(*subject_handle,
2857 answer->GetChars() + position,
2858 prev,
2859 start);
2860 position += start - prev;
2861 }
2862 prev = end;
2863 next = end;
2864 // Continue from where the match ended, unless it was an empty match.
2865 if (start == end) {
2866 next++;
2867 if (next > length) break;
2868 }
2869 match = RegExpImpl::Exec(regexp_handle,
2870 subject_handle,
2871 next,
2872 last_match_info_handle);
2873 if (match.is_null()) return Failure::Exception();
2874 if (match->IsNull()) break;
2875
2876 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002877 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002878 {
2879 AssertNoAllocation match_info_array_is_not_in_a_handle;
2880 FixedArray* match_info_array =
2881 FixedArray::cast(last_match_info_handle->elements());
2882 start = RegExpImpl::GetCapture(match_info_array, 0);
2883 end = RegExpImpl::GetCapture(match_info_array, 1);
2884 }
2885 } while (true);
2886
2887 if (prev < length) {
2888 // Add substring subject[prev;length] to answer string.
2889 String::WriteToFlat(*subject_handle,
2890 answer->GetChars() + position,
2891 prev,
2892 length);
2893 position += length - prev;
2894 }
2895
2896 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002897 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002898 }
2899
2900 // Shorten string and fill
2901 int string_size = ResultSeqString::SizeFor(position);
2902 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2903 int delta = allocated_string_size - string_size;
2904
2905 answer->set_length(position);
2906 if (delta == 0) return *answer;
2907
2908 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002909 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002910
2911 return *answer;
2912}
2913
2914
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002915RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002916 ASSERT(args.length() == 4);
2917
2918 CONVERT_CHECKED(String, subject, args[0]);
2919 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002920 Object* flat_subject;
2921 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2922 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2923 return maybe_flat_subject;
2924 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002925 }
2926 subject = String::cast(flat_subject);
2927 }
2928
2929 CONVERT_CHECKED(String, replacement, args[2]);
2930 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002931 Object* flat_replacement;
2932 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2933 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2934 return maybe_flat_replacement;
2935 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002936 }
2937 replacement = String::cast(flat_replacement);
2938 }
2939
2940 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2941 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2942
2943 ASSERT(last_match_info->HasFastElements());
2944
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002945 if (replacement->length() == 0) {
2946 if (subject->HasOnlyAsciiChars()) {
2947 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002948 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002949 } else {
2950 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002951 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002952 }
2953 }
2954
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002955 return StringReplaceRegExpWithString(isolate,
2956 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002957 regexp,
2958 replacement,
2959 last_match_info);
2960}
2961
2962
ager@chromium.org7c537e22008-10-16 08:43:32 +00002963// Perform string match of pattern on subject, starting at start index.
2964// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002965// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002966int Runtime::StringMatch(Isolate* isolate,
2967 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00002968 Handle<String> pat,
2969 int start_index) {
2970 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002971 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002972
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002973 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002974 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002975
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002976 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002977 if (start_index + pattern_length > subject_length) return -1;
2978
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002979 if (!sub->IsFlat()) FlattenString(sub);
2980 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002981
ager@chromium.org7c537e22008-10-16 08:43:32 +00002982 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002983 // Extract flattened substrings of cons strings before determining asciiness.
2984 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002985 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002986 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002987 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002988
ager@chromium.org7c537e22008-10-16 08:43:32 +00002989 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002990 if (seq_pat->IsAsciiRepresentation()) {
2991 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2992 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002993 return SearchString(isolate,
2994 seq_sub->ToAsciiVector(),
2995 pat_vector,
2996 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002997 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002998 return SearchString(isolate,
2999 seq_sub->ToUC16Vector(),
3000 pat_vector,
3001 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003002 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003003 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
3004 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003005 return SearchString(isolate,
3006 seq_sub->ToAsciiVector(),
3007 pat_vector,
3008 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003009 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003010 return SearchString(isolate,
3011 seq_sub->ToUC16Vector(),
3012 pat_vector,
3013 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003014}
3015
3016
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003017RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003018 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003019 ASSERT(args.length() == 3);
3020
ager@chromium.org7c537e22008-10-16 08:43:32 +00003021 CONVERT_ARG_CHECKED(String, sub, 0);
3022 CONVERT_ARG_CHECKED(String, pat, 1);
3023
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003024 Object* index = args[2];
3025 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003026 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003027
ager@chromium.org870a0b62008-11-04 11:43:05 +00003028 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003029 int position =
3030 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003031 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003032}
3033
3034
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003035template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003036static int StringMatchBackwards(Vector<const schar> subject,
3037 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003038 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003039 int pattern_length = pattern.length();
3040 ASSERT(pattern_length >= 1);
3041 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003042
3043 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003044 for (int i = 0; i < pattern_length; i++) {
3045 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003046 if (c > String::kMaxAsciiCharCode) {
3047 return -1;
3048 }
3049 }
3050 }
3051
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003052 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003053 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003054 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003055 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003056 while (j < pattern_length) {
3057 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003058 break;
3059 }
3060 j++;
3061 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003062 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003063 return i;
3064 }
3065 }
3066 return -1;
3067}
3068
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003069RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003070 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003071 ASSERT(args.length() == 3);
3072
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003073 CONVERT_ARG_CHECKED(String, sub, 0);
3074 CONVERT_ARG_CHECKED(String, pat, 1);
3075
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003076 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003077 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003078 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003079
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003080 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003081 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003082
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003083 if (start_index + pat_length > sub_length) {
3084 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003085 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003086
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003087 if (pat_length == 0) {
3088 return Smi::FromInt(start_index);
3089 }
3090
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003091 if (!sub->IsFlat()) FlattenString(sub);
3092 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003093
3094 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3095
3096 int position = -1;
3097
3098 if (pat->IsAsciiRepresentation()) {
3099 Vector<const char> pat_vector = pat->ToAsciiVector();
3100 if (sub->IsAsciiRepresentation()) {
3101 position = StringMatchBackwards(sub->ToAsciiVector(),
3102 pat_vector,
3103 start_index);
3104 } else {
3105 position = StringMatchBackwards(sub->ToUC16Vector(),
3106 pat_vector,
3107 start_index);
3108 }
3109 } else {
3110 Vector<const uc16> pat_vector = pat->ToUC16Vector();
3111 if (sub->IsAsciiRepresentation()) {
3112 position = StringMatchBackwards(sub->ToAsciiVector(),
3113 pat_vector,
3114 start_index);
3115 } else {
3116 position = StringMatchBackwards(sub->ToUC16Vector(),
3117 pat_vector,
3118 start_index);
3119 }
3120 }
3121
3122 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003123}
3124
3125
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003126RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003127 NoHandleAllocation ha;
3128 ASSERT(args.length() == 2);
3129
3130 CONVERT_CHECKED(String, str1, args[0]);
3131 CONVERT_CHECKED(String, str2, args[1]);
3132
3133 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003134 int str1_length = str1->length();
3135 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003136
3137 // Decide trivial cases without flattening.
3138 if (str1_length == 0) {
3139 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3140 return Smi::FromInt(-str2_length);
3141 } else {
3142 if (str2_length == 0) return Smi::FromInt(str1_length);
3143 }
3144
3145 int end = str1_length < str2_length ? str1_length : str2_length;
3146
3147 // No need to flatten if we are going to find the answer on the first
3148 // character. At this point we know there is at least one character
3149 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003150 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003151 if (d != 0) return Smi::FromInt(d);
3152
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003153 str1->TryFlatten();
3154 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003155
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003156 StringInputBuffer& buf1 =
3157 *isolate->runtime_state()->string_locale_compare_buf1();
3158 StringInputBuffer& buf2 =
3159 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003160
3161 buf1.Reset(str1);
3162 buf2.Reset(str2);
3163
3164 for (int i = 0; i < end; i++) {
3165 uint16_t char1 = buf1.GetNext();
3166 uint16_t char2 = buf2.GetNext();
3167 if (char1 != char2) return Smi::FromInt(char1 - char2);
3168 }
3169
3170 return Smi::FromInt(str1_length - str2_length);
3171}
3172
3173
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003174RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003175 NoHandleAllocation ha;
3176 ASSERT(args.length() == 3);
3177
3178 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003179 int start, end;
3180 // We have a fast integer-only case here to avoid a conversion to double in
3181 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003182 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3183 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3184 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3185 start = from_number;
3186 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003187 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003188 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3189 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003190 start = FastD2I(from_number);
3191 end = FastD2I(to_number);
3192 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003193 RUNTIME_ASSERT(end >= start);
3194 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003195 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003196 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003197 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003198}
3199
3200
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003201RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003202 ASSERT_EQ(3, args.length());
3203
3204 CONVERT_ARG_CHECKED(String, subject, 0);
3205 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3206 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3207 HandleScope handles;
3208
3209 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3210
3211 if (match.is_null()) {
3212 return Failure::Exception();
3213 }
3214 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003215 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003216 }
3217 int length = subject->length();
3218
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003219 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003220 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003221 int start;
3222 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003223 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003224 {
3225 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003226 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003227 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3228 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3229 }
3230 offsets.Add(start);
3231 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003232 if (start == end) if (++end > length) break;
3233 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003234 if (match.is_null()) {
3235 return Failure::Exception();
3236 }
3237 } while (!match->IsNull());
3238 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003239 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003240 Handle<String> substring = isolate->factory()->
3241 NewSubString(subject, offsets.at(0), offsets.at(1));
3242 elements->set(0, *substring);
3243 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003244 int from = offsets.at(i * 2);
3245 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003246 Handle<String> substring = isolate->factory()->
3247 NewProperSubString(subject, from, to);
3248 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003249 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003250 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003251 result->set_length(Smi::FromInt(matches));
3252 return *result;
3253}
3254
3255
lrn@chromium.org25156de2010-04-06 13:10:27 +00003256// Two smis before and after the match, for very long strings.
3257const int kMaxBuilderEntriesPerRegExpMatch = 5;
3258
3259
3260static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3261 Handle<JSArray> last_match_info,
3262 int match_start,
3263 int match_end) {
3264 // Fill last_match_info with a single capture.
3265 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3266 AssertNoAllocation no_gc;
3267 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3268 RegExpImpl::SetLastCaptureCount(elements, 2);
3269 RegExpImpl::SetLastInput(elements, *subject);
3270 RegExpImpl::SetLastSubject(elements, *subject);
3271 RegExpImpl::SetCapture(elements, 0, match_start);
3272 RegExpImpl::SetCapture(elements, 1, match_end);
3273}
3274
3275
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003276template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003277static bool SearchStringMultiple(Isolate* isolate,
3278 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003279 Vector<const PatternChar> pattern,
3280 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003281 FixedArrayBuilder* builder,
3282 int* match_pos) {
3283 int pos = *match_pos;
3284 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003285 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003286 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003287 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003288 while (pos <= max_search_start) {
3289 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3290 *match_pos = pos;
3291 return false;
3292 }
3293 // Position of end of previous match.
3294 int match_end = pos + pattern_length;
3295 int new_pos = search.Search(subject, match_end);
3296 if (new_pos >= 0) {
3297 // A match.
3298 if (new_pos > match_end) {
3299 ReplacementStringBuilder::AddSubjectSlice(builder,
3300 match_end,
3301 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003302 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003303 pos = new_pos;
3304 builder->Add(pattern_string);
3305 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003306 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003307 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003308 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003309
lrn@chromium.org25156de2010-04-06 13:10:27 +00003310 if (pos < max_search_start) {
3311 ReplacementStringBuilder::AddSubjectSlice(builder,
3312 pos + pattern_length,
3313 subject_length);
3314 }
3315 *match_pos = pos;
3316 return true;
3317}
3318
3319
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003320static bool SearchStringMultiple(Isolate* isolate,
3321 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003322 Handle<String> pattern,
3323 Handle<JSArray> last_match_info,
3324 FixedArrayBuilder* builder) {
3325 ASSERT(subject->IsFlat());
3326 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003327
3328 // Treating as if a previous match was before first character.
3329 int match_pos = -pattern->length();
3330
3331 for (;;) { // Break when search complete.
3332 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3333 AssertNoAllocation no_gc;
3334 if (subject->IsAsciiRepresentation()) {
3335 Vector<const char> subject_vector = subject->ToAsciiVector();
3336 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003337 if (SearchStringMultiple(isolate,
3338 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003339 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003340 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003341 builder,
3342 &match_pos)) break;
3343 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003344 if (SearchStringMultiple(isolate,
3345 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003346 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003347 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003348 builder,
3349 &match_pos)) break;
3350 }
3351 } else {
3352 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3353 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003354 if (SearchStringMultiple(isolate,
3355 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003356 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003357 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003358 builder,
3359 &match_pos)) break;
3360 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003361 if (SearchStringMultiple(isolate,
3362 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003363 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003364 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003365 builder,
3366 &match_pos)) break;
3367 }
3368 }
3369 }
3370
3371 if (match_pos >= 0) {
3372 SetLastMatchInfoNoCaptures(subject,
3373 last_match_info,
3374 match_pos,
3375 match_pos + pattern->length());
3376 return true;
3377 }
3378 return false; // No matches at all.
3379}
3380
3381
3382static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003383 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003384 Handle<String> subject,
3385 Handle<JSRegExp> regexp,
3386 Handle<JSArray> last_match_array,
3387 FixedArrayBuilder* builder) {
3388 ASSERT(subject->IsFlat());
3389 int match_start = -1;
3390 int match_end = 0;
3391 int pos = 0;
3392 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3393 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3394
3395 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003396 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003397 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003398 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003399
3400 for (;;) { // Break on failure, return on exception.
3401 RegExpImpl::IrregexpResult result =
3402 RegExpImpl::IrregexpExecOnce(regexp,
3403 subject,
3404 pos,
3405 register_vector);
3406 if (result == RegExpImpl::RE_SUCCESS) {
3407 match_start = register_vector[0];
3408 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3409 if (match_end < match_start) {
3410 ReplacementStringBuilder::AddSubjectSlice(builder,
3411 match_end,
3412 match_start);
3413 }
3414 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003415 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003416 if (!first) {
3417 builder->Add(*isolate->factory()->NewProperSubString(subject,
3418 match_start,
3419 match_end));
3420 } else {
3421 builder->Add(*isolate->factory()->NewSubString(subject,
3422 match_start,
3423 match_end));
3424 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003425 if (match_start != match_end) {
3426 pos = match_end;
3427 } else {
3428 pos = match_end + 1;
3429 if (pos > subject_length) break;
3430 }
3431 } else if (result == RegExpImpl::RE_FAILURE) {
3432 break;
3433 } else {
3434 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3435 return result;
3436 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003437 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003438 }
3439
3440 if (match_start >= 0) {
3441 if (match_end < subject_length) {
3442 ReplacementStringBuilder::AddSubjectSlice(builder,
3443 match_end,
3444 subject_length);
3445 }
3446 SetLastMatchInfoNoCaptures(subject,
3447 last_match_array,
3448 match_start,
3449 match_end);
3450 return RegExpImpl::RE_SUCCESS;
3451 } else {
3452 return RegExpImpl::RE_FAILURE; // No matches at all.
3453 }
3454}
3455
3456
3457static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003458 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003459 Handle<String> subject,
3460 Handle<JSRegExp> regexp,
3461 Handle<JSArray> last_match_array,
3462 FixedArrayBuilder* builder) {
3463
3464 ASSERT(subject->IsFlat());
3465 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3466 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3467
3468 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003469 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003470
3471 RegExpImpl::IrregexpResult result =
3472 RegExpImpl::IrregexpExecOnce(regexp,
3473 subject,
3474 0,
3475 register_vector);
3476
3477 int capture_count = regexp->CaptureCount();
3478 int subject_length = subject->length();
3479
3480 // Position to search from.
3481 int pos = 0;
3482 // End of previous match. Differs from pos if match was empty.
3483 int match_end = 0;
3484 if (result == RegExpImpl::RE_SUCCESS) {
3485 // Need to keep a copy of the previous match for creating last_match_info
3486 // at the end, so we have two vectors that we swap between.
3487 OffsetsVector registers2(required_registers);
3488 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003489 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003490 do {
3491 int match_start = register_vector[0];
3492 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3493 if (match_end < match_start) {
3494 ReplacementStringBuilder::AddSubjectSlice(builder,
3495 match_end,
3496 match_start);
3497 }
3498 match_end = register_vector[1];
3499
3500 {
3501 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003502 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003503 // Arguments array to replace function is match, captures, index and
3504 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003505 Handle<FixedArray> elements =
3506 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003507 Handle<String> match;
3508 if (!first) {
3509 match = isolate->factory()->NewProperSubString(subject,
3510 match_start,
3511 match_end);
3512 } else {
3513 match = isolate->factory()->NewSubString(subject,
3514 match_start,
3515 match_end);
3516 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003517 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003518 for (int i = 1; i <= capture_count; i++) {
3519 int start = register_vector[i * 2];
3520 if (start >= 0) {
3521 int end = register_vector[i * 2 + 1];
3522 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003523 Handle<String> substring;
3524 if (!first) {
3525 substring = isolate->factory()->NewProperSubString(subject,
3526 start,
3527 end);
3528 } else {
3529 substring = isolate->factory()->NewSubString(subject, start, end);
3530 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003531 elements->set(i, *substring);
3532 } else {
3533 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003534 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003535 }
3536 }
3537 elements->set(capture_count + 1, Smi::FromInt(match_start));
3538 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003539 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003540 }
3541 // Swap register vectors, so the last successful match is in
3542 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003543 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003544 prev_register_vector = register_vector;
3545 register_vector = tmp;
3546
3547 if (match_end > match_start) {
3548 pos = match_end;
3549 } else {
3550 pos = match_end + 1;
3551 if (pos > subject_length) {
3552 break;
3553 }
3554 }
3555
3556 result = RegExpImpl::IrregexpExecOnce(regexp,
3557 subject,
3558 pos,
3559 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003560 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003561 } while (result == RegExpImpl::RE_SUCCESS);
3562
3563 if (result != RegExpImpl::RE_EXCEPTION) {
3564 // Finished matching, with at least one match.
3565 if (match_end < subject_length) {
3566 ReplacementStringBuilder::AddSubjectSlice(builder,
3567 match_end,
3568 subject_length);
3569 }
3570
3571 int last_match_capture_count = (capture_count + 1) * 2;
3572 int last_match_array_size =
3573 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3574 last_match_array->EnsureSize(last_match_array_size);
3575 AssertNoAllocation no_gc;
3576 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3577 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3578 RegExpImpl::SetLastSubject(elements, *subject);
3579 RegExpImpl::SetLastInput(elements, *subject);
3580 for (int i = 0; i < last_match_capture_count; i++) {
3581 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3582 }
3583 return RegExpImpl::RE_SUCCESS;
3584 }
3585 }
3586 // No matches at all, return failure or exception result directly.
3587 return result;
3588}
3589
3590
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003591RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003592 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003593 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003594
3595 CONVERT_ARG_CHECKED(String, subject, 1);
3596 if (!subject->IsFlat()) { FlattenString(subject); }
3597 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3598 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3599 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3600
3601 ASSERT(last_match_info->HasFastElements());
3602 ASSERT(regexp->GetFlags().is_global());
3603 Handle<FixedArray> result_elements;
3604 if (result_array->HasFastElements()) {
3605 result_elements =
3606 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003607 }
3608 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003609 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003610 }
3611 FixedArrayBuilder builder(result_elements);
3612
3613 if (regexp->TypeTag() == JSRegExp::ATOM) {
3614 Handle<String> pattern(
3615 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003616 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003617 if (SearchStringMultiple(isolate, subject, pattern,
3618 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003619 return *builder.ToJSArray(result_array);
3620 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003621 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003622 }
3623
3624 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3625
3626 RegExpImpl::IrregexpResult result;
3627 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003628 result = SearchRegExpNoCaptureMultiple(isolate,
3629 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003630 regexp,
3631 last_match_info,
3632 &builder);
3633 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003634 result = SearchRegExpMultiple(isolate,
3635 subject,
3636 regexp,
3637 last_match_info,
3638 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003639 }
3640 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003641 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003642 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3643 return Failure::Exception();
3644}
3645
3646
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003647RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003648 NoHandleAllocation ha;
3649 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003650 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003651 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003652
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003653 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003654 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003655 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003656 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003657 // Character array used for conversion.
3658 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003659 return isolate->heap()->
3660 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003661 }
3662 }
3663
3664 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003665 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003666 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003667 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003668 }
3669 if (isinf(value)) {
3670 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003671 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003672 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003673 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003674 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003675 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003676 MaybeObject* result =
3677 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003678 DeleteArray(str);
3679 return result;
3680}
3681
3682
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003683RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003684 NoHandleAllocation ha;
3685 ASSERT(args.length() == 2);
3686
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003687 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003688 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003689 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003690 }
3691 if (isinf(value)) {
3692 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003693 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003694 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003695 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003696 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003697 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003698 int f = FastD2I(f_number);
3699 RUNTIME_ASSERT(f >= 0);
3700 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003701 MaybeObject* res =
3702 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003703 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003704 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003705}
3706
3707
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003708RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003709 NoHandleAllocation ha;
3710 ASSERT(args.length() == 2);
3711
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003712 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003713 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003714 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003715 }
3716 if (isinf(value)) {
3717 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003718 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003719 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003720 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003721 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003722 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003723 int f = FastD2I(f_number);
3724 RUNTIME_ASSERT(f >= -1 && f <= 20);
3725 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003726 MaybeObject* res =
3727 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003728 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003729 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003730}
3731
3732
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003733RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003734 NoHandleAllocation ha;
3735 ASSERT(args.length() == 2);
3736
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003737 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003738 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003739 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003740 }
3741 if (isinf(value)) {
3742 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003743 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003744 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003745 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003746 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003747 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003748 int f = FastD2I(f_number);
3749 RUNTIME_ASSERT(f >= 1 && f <= 21);
3750 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003751 MaybeObject* res =
3752 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003753 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003754 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003755}
3756
3757
3758// Returns a single character string where first character equals
3759// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003760static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003761 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003762 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003763 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003764 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003765 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003766 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003767}
3768
3769
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003770MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
3771 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003772 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003773 // Handle [] indexing on Strings
3774 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003775 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3776 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003777 }
3778
3779 // Handle [] indexing on String objects
3780 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003781 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3782 Handle<Object> result =
3783 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3784 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003785 }
3786
3787 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003788 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003789 return prototype->GetElement(index);
3790 }
3791
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003792 return GetElement(object, index);
3793}
3794
3795
lrn@chromium.org303ada72010-10-27 09:33:13 +00003796MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003797 return object->GetElement(index);
3798}
3799
3800
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003801MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
3802 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003803 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003804 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003805
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003806 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003807 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003808 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003809 isolate->factory()->NewTypeError("non_object_property_load",
3810 HandleVector(args, 2));
3811 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003812 }
3813
3814 // Check if the given key is an array index.
3815 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003816 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003817 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003818 }
3819
3820 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003821 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003822 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003823 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003824 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003825 bool has_pending_exception = false;
3826 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003827 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003828 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003829 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003830 }
3831
ager@chromium.org32912102009-01-16 10:38:43 +00003832 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003833 // the element if so.
3834 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003835 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003836 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003837 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003838 }
3839}
3840
3841
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003842RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003843 NoHandleAllocation ha;
3844 ASSERT(args.length() == 2);
3845
3846 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003847 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003848
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003849 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003850}
3851
3852
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003853// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003854RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003855 NoHandleAllocation ha;
3856 ASSERT(args.length() == 2);
3857
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003858 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003859 // itself.
3860 //
3861 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003862 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003863 // global proxy object never has properties. This is the case
3864 // because the global proxy object forwards everything to its hidden
3865 // prototype including local lookups.
3866 //
3867 // Additionally, we need to make sure that we do not cache results
3868 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003869 if (args[0]->IsJSObject() &&
3870 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003871 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003872 args[1]->IsString()) {
3873 JSObject* receiver = JSObject::cast(args[0]);
3874 String* key = String::cast(args[1]);
3875 if (receiver->HasFastProperties()) {
3876 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003877 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003878 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
3879 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003880 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003881 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003882 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003883 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003884 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003885 LookupResult result;
3886 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003887 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003888 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003889 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003890 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003891 }
3892 } else {
3893 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003894 StringDictionary* dictionary = receiver->property_dictionary();
3895 int entry = dictionary->FindEntry(key);
3896 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003897 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003898 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003899 if (!receiver->IsGlobalObject()) return value;
3900 value = JSGlobalPropertyCell::cast(value)->value();
3901 if (!value->IsTheHole()) return value;
3902 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003903 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003904 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003905 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3906 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003907 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003908 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003909 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003910 if (index >= 0 && index < str->length()) {
3911 Handle<Object> result = GetCharAt(str, index);
3912 return *result;
3913 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003914 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003915
3916 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003917 return Runtime::GetObjectProperty(isolate,
3918 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00003919 args.at<Object>(1));
3920}
3921
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003922// Implements part of 8.12.9 DefineOwnProperty.
3923// There are 3 cases that lead here:
3924// Step 4b - define a new accessor property.
3925// Steps 9c & 12 - replace an existing data property with an accessor property.
3926// Step 12 - update an existing accessor property with an accessor or generic
3927// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003928RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003929 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003930 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003931 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3932 CONVERT_CHECKED(String, name, args[1]);
3933 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003934 Object* fun = args[3];
3935 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00003936 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3937 int unchecked = flag_attr->value();
3938 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3939 RUNTIME_ASSERT(!obj->IsNull());
3940 LookupResult result;
3941 obj->LocalLookupRealNamedProperty(name, &result);
3942
3943 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3944 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3945 // delete it to avoid running into trouble in DefineAccessor, which
3946 // handles this incorrectly if the property is readonly (does nothing)
3947 if (result.IsProperty() &&
3948 (result.type() == FIELD || result.type() == NORMAL
3949 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003950 Object* ok;
3951 { MaybeObject* maybe_ok =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003952 obj->DeleteProperty(name, JSReceiver::NORMAL_DELETION);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003953 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3954 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003955 }
3956 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3957}
3958
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003959// Implements part of 8.12.9 DefineOwnProperty.
3960// There are 3 cases that lead here:
3961// Step 4a - define a new data property.
3962// Steps 9b & 12 - replace an existing accessor property with a data property.
3963// Step 12 - update an existing data property with a data or generic
3964// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003965RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003966 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003967 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003968 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3969 CONVERT_ARG_CHECKED(String, name, 1);
3970 Handle<Object> obj_value = args.at<Object>(2);
3971
3972 CONVERT_CHECKED(Smi, flag, args[3]);
3973 int unchecked = flag->value();
3974 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3975
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003976 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3977
3978 // Check if this is an element.
3979 uint32_t index;
3980 bool is_element = name->AsArrayIndex(&index);
3981
3982 // Special case for elements if any of the flags are true.
3983 // If elements are in fast case we always implicitly assume that:
3984 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3985 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3986 is_element) {
3987 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003988 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003989 // We do not need to do access checks here since these has already
3990 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003991 Handle<Object> proto(js_object->GetPrototype());
3992 // If proxy is detached, ignore the assignment. Alternatively,
3993 // we could throw an exception.
3994 if (proto->IsNull()) return *obj_value;
3995 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003996 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003997 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003998 // Make sure that we never go back to fast case.
3999 dictionary->set_requires_slow_elements();
4000 PropertyDetails details = PropertyDetails(attr, NORMAL);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004001 Handle<NumberDictionary> extended_dictionary =
4002 NumberDictionarySet(dictionary, index, obj_value, details);
4003 if (*extended_dictionary != *dictionary) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004004 if (js_object->GetElementsKind() ==
4005 JSObject::NON_STRICT_ARGUMENTS_ELEMENTS) {
4006 FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
4007 } else {
4008 js_object->set_elements(*extended_dictionary);
4009 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004010 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004011 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004012 }
4013
ager@chromium.org5c838252010-02-19 08:53:10 +00004014 LookupResult result;
whesse@chromium.org7b260152011-06-20 15:33:18 +00004015 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004016
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004017 // To be compatible with safari we do not change the value on API objects
4018 // in defineProperty. Firefox disagrees here, and actually changes the value.
4019 if (result.IsProperty() &&
4020 (result.type() == CALLBACKS) &&
4021 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004022 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004023 }
4024
ager@chromium.org5c838252010-02-19 08:53:10 +00004025 // Take special care when attributes are different and there is already
4026 // a property. For simplicity we normalize the property which enables us
4027 // to not worry about changing the instance_descriptor and creating a new
4028 // map. The current version of SetObjectProperty does not handle attributes
4029 // correctly in the case where a property is a field and is reset with
4030 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004031 if (result.IsProperty() &&
4032 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004033 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004034 if (js_object->IsJSGlobalProxy()) {
4035 // Since the result is a property, the prototype will exist so
4036 // we don't have to check for null.
4037 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004038 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004039 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004040 // Use IgnoreAttributes version since a readonly property may be
4041 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004042 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4043 *obj_value,
4044 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004045 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004046
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004047 return Runtime::ForceSetObjectProperty(isolate,
4048 js_object,
4049 name,
4050 obj_value,
4051 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004052}
4053
4054
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004055// Special case for elements if any of the flags are true.
4056// If elements are in fast case we always implicitly assume that:
4057// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4058static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
4059 Handle<JSObject> js_object,
4060 uint32_t index,
4061 Handle<Object> value,
4062 PropertyAttributes attr) {
4063 // Normalize the elements to enable attributes on the property.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004064 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004065 // Make sure that we never go back to fast case.
4066 dictionary->set_requires_slow_elements();
4067 PropertyDetails details = PropertyDetails(attr, NORMAL);
4068 Handle<NumberDictionary> extended_dictionary =
4069 NumberDictionarySet(dictionary, index, value, details);
4070 if (*extended_dictionary != *dictionary) {
4071 js_object->set_elements(*extended_dictionary);
4072 }
4073 return *value;
4074}
4075
4076
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004077MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4078 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004079 Handle<Object> key,
4080 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004081 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004082 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004083 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004084
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004085 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004086 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004087 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004088 isolate->factory()->NewTypeError("non_object_property_store",
4089 HandleVector(args, 2));
4090 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004091 }
4092
4093 // If the object isn't a JavaScript object, we ignore the store.
4094 if (!object->IsJSObject()) return *value;
4095
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004096 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4097
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004098 // Check if the given key is an array index.
4099 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004100 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004101 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4102 // of a string using [] notation. We need to support this too in
4103 // JavaScript.
4104 // In the case of a String object we just need to redirect the assignment to
4105 // the underlying string if the index is in range. Since the underlying
4106 // string does nothing with the assignment then we can ignore such
4107 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004108 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004109 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004110 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004111
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004112 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4113 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
4114 }
4115
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004116 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004117 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004118 return *value;
4119 }
4120
4121 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004122 Handle<Object> result;
4123 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004124 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4125 return NormalizeObjectSetElement(isolate,
4126 js_object,
4127 index,
4128 value,
4129 attr);
4130 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004131 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004132 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004133 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004134 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004135 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004136 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004137 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004138 return *value;
4139 }
4140
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004141 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004142 bool has_pending_exception = false;
4143 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4144 if (has_pending_exception) return Failure::Exception();
4145 Handle<String> name = Handle<String>::cast(converted);
4146
4147 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004148 return js_object->SetElement(index, *value, strict_mode, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004149 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004150 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004151 }
4152}
4153
4154
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004155MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4156 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004157 Handle<Object> key,
4158 Handle<Object> value,
4159 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004160 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004161
4162 // Check if the given key is an array index.
4163 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004164 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004165 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4166 // of a string using [] notation. We need to support this too in
4167 // JavaScript.
4168 // In the case of a String object we just need to redirect the assignment to
4169 // the underlying string if the index is in range. Since the underlying
4170 // string does nothing with the assignment then we can ignore such
4171 // assignments.
4172 if (js_object->IsStringObjectWithCharacterAt(index)) {
4173 return *value;
4174 }
4175
whesse@chromium.org7b260152011-06-20 15:33:18 +00004176 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004177 }
4178
4179 if (key->IsString()) {
4180 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004181 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004182 } else {
4183 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004184 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004185 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4186 *value,
4187 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004188 }
4189 }
4190
4191 // Call-back into JavaScript to convert the key to a string.
4192 bool has_pending_exception = false;
4193 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4194 if (has_pending_exception) return Failure::Exception();
4195 Handle<String> name = Handle<String>::cast(converted);
4196
4197 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004198 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004199 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004200 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004201 }
4202}
4203
4204
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004205MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004206 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004207 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004208 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004209
4210 // Check if the given key is an array index.
4211 uint32_t index;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004212 if (receiver->IsJSObject() && key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004213 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4214 // characters of a string using [] notation. In the case of a
4215 // String object we just need to redirect the deletion to the
4216 // underlying string if the index is in range. Since the
4217 // underlying string does nothing with the deletion, we can ignore
4218 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004219 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004220 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004221 }
4222
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004223 return JSObject::cast(*receiver)->DeleteElement(
4224 index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004225 }
4226
4227 Handle<String> key_string;
4228 if (key->IsString()) {
4229 key_string = Handle<String>::cast(key);
4230 } else {
4231 // Call-back into JavaScript to convert the key to a string.
4232 bool has_pending_exception = false;
4233 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4234 if (has_pending_exception) return Failure::Exception();
4235 key_string = Handle<String>::cast(converted);
4236 }
4237
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004238 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004239 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004240}
4241
4242
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004243RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004244 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004245 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004246
4247 Handle<Object> object = args.at<Object>(0);
4248 Handle<Object> key = args.at<Object>(1);
4249 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004250 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004251 RUNTIME_ASSERT(
4252 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004253 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004254 PropertyAttributes attributes =
4255 static_cast<PropertyAttributes>(unchecked_attributes);
4256
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004257 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004258 if (args.length() == 5) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004259 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004260 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4261 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004262 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004263 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004264
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004265 return Runtime::SetObjectProperty(isolate,
4266 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004267 key,
4268 value,
4269 attributes,
4270 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004271}
4272
4273
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004274// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004275// This is used to decide if we should transform null and undefined
4276// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004277RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004278 NoHandleAllocation ha;
4279 RUNTIME_ASSERT(args.length() == 1);
4280
4281 Handle<Object> object = args.at<Object>(0);
4282
4283 if (object->IsJSFunction()) {
4284 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004285 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004286 }
4287 return isolate->heap()->undefined_value();
4288}
4289
4290
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004291// Set a local property, even if it is READ_ONLY. If the property does not
4292// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004293RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004294 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004295 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004296 CONVERT_CHECKED(JSObject, object, args[0]);
4297 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004298 // Compute attributes.
4299 PropertyAttributes attributes = NONE;
4300 if (args.length() == 4) {
4301 CONVERT_CHECKED(Smi, value_obj, args[3]);
4302 int unchecked_value = value_obj->value();
4303 // Only attribute bits should be set.
4304 RUNTIME_ASSERT(
4305 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4306 attributes = static_cast<PropertyAttributes>(unchecked_value);
4307 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004308
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004309 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004310 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004311}
4312
4313
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004314RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004315 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004316 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004317
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004318 CONVERT_CHECKED(JSReceiver, object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004319 CONVERT_CHECKED(String, key, args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004320 CONVERT_SMI_ARG_CHECKED(strict, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004321 return object->DeleteProperty(key, (strict == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004322 ? JSReceiver::STRICT_DELETION
4323 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004324}
4325
4326
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004327static Object* HasLocalPropertyImplementation(Isolate* isolate,
4328 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004329 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004330 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004331 // Handle hidden prototypes. If there's a hidden prototype above this thing
4332 // then we have to check it for properties, because they are supposed to
4333 // look like they are on this object.
4334 Handle<Object> proto(object->GetPrototype());
4335 if (proto->IsJSObject() &&
4336 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004337 return HasLocalPropertyImplementation(isolate,
4338 Handle<JSObject>::cast(proto),
4339 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004340 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004341 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004342}
4343
4344
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004345RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004346 NoHandleAllocation ha;
4347 ASSERT(args.length() == 2);
4348 CONVERT_CHECKED(String, key, args[1]);
4349
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004350 uint32_t index;
4351 const bool key_is_array_index = key->AsArrayIndex(&index);
4352
ager@chromium.org9085a012009-05-11 19:22:57 +00004353 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004354 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004355 if (obj->IsJSObject()) {
4356 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004357 // Fast case: either the key is a real named property or it is not
4358 // an array index and there are no interceptors or hidden
4359 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004360 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004361 Map* map = object->map();
4362 if (!key_is_array_index &&
4363 !map->has_named_interceptor() &&
4364 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4365 return isolate->heap()->false_value();
4366 }
4367 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004368 HandleScope scope(isolate);
4369 return HasLocalPropertyImplementation(isolate,
4370 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004371 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004372 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004373 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004374 String* string = String::cast(obj);
4375 if (index < static_cast<uint32_t>(string->length())) {
4376 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004377 }
4378 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004379 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004380}
4381
4382
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004383RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004384 NoHandleAllocation na;
4385 ASSERT(args.length() == 2);
4386
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004387 // Only JS receivers can have properties.
4388 if (args[0]->IsJSReceiver()) {
4389 JSReceiver* receiver = JSReceiver::cast(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004390 CONVERT_CHECKED(String, key, args[1]);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004391 if (receiver->HasProperty(key)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004392 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004393 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004394}
4395
4396
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004397RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004398 NoHandleAllocation na;
4399 ASSERT(args.length() == 2);
4400
4401 // Only JS objects can have elements.
4402 if (args[0]->IsJSObject()) {
4403 JSObject* object = JSObject::cast(args[0]);
4404 CONVERT_CHECKED(Smi, index_obj, args[1]);
4405 uint32_t index = index_obj->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004406 if (object->HasElement(index)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004407 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004408 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004409}
4410
4411
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004412RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004413 NoHandleAllocation ha;
4414 ASSERT(args.length() == 2);
4415
4416 CONVERT_CHECKED(JSObject, object, args[0]);
4417 CONVERT_CHECKED(String, key, args[1]);
4418
4419 uint32_t index;
4420 if (key->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004421 return isolate->heap()->ToBoolean(object->HasElement(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004422 }
4423
ager@chromium.org870a0b62008-11-04 11:43:05 +00004424 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004425 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004426}
4427
4428
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004429RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004430 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004431 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004432 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004433 return *GetKeysFor(object);
4434}
4435
4436
4437// Returns either a FixedArray as Runtime_GetPropertyNames,
4438// or, if the given object has an enum cache that contains
4439// all enumerable properties of the object and its prototypes
4440// have none, the map of the object. This is used to speed up
4441// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004442RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004443 ASSERT(args.length() == 1);
4444
4445 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4446
4447 if (raw_object->IsSimpleEnum()) return raw_object->map();
4448
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004449 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004450 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004451 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4452 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004453
4454 // Test again, since cache may have been built by preceding call.
4455 if (object->IsSimpleEnum()) return object->map();
4456
4457 return *content;
4458}
4459
4460
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004461// Find the length of the prototype chain that is to to handled as one. If a
4462// prototype object is hidden it is to be viewed as part of the the object it
4463// is prototype for.
4464static int LocalPrototypeChainLength(JSObject* obj) {
4465 int count = 1;
4466 Object* proto = obj->GetPrototype();
4467 while (proto->IsJSObject() &&
4468 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4469 count++;
4470 proto = JSObject::cast(proto)->GetPrototype();
4471 }
4472 return count;
4473}
4474
4475
4476// Return the names of the local named properties.
4477// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004478RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004479 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004480 ASSERT(args.length() == 1);
4481 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004482 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004483 }
4484 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4485
4486 // Skip the global proxy as it has no properties and always delegates to the
4487 // real global object.
4488 if (obj->IsJSGlobalProxy()) {
4489 // Only collect names if access is permitted.
4490 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004491 !isolate->MayNamedAccess(*obj,
4492 isolate->heap()->undefined_value(),
4493 v8::ACCESS_KEYS)) {
4494 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4495 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004496 }
4497 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4498 }
4499
4500 // Find the number of objects making up this.
4501 int length = LocalPrototypeChainLength(*obj);
4502
4503 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004504 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004505 int total_property_count = 0;
4506 Handle<JSObject> jsproto = obj;
4507 for (int i = 0; i < length; i++) {
4508 // Only collect names if access is permitted.
4509 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004510 !isolate->MayNamedAccess(*jsproto,
4511 isolate->heap()->undefined_value(),
4512 v8::ACCESS_KEYS)) {
4513 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4514 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004515 }
4516 int n;
4517 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4518 local_property_count[i] = n;
4519 total_property_count += n;
4520 if (i < length - 1) {
4521 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4522 }
4523 }
4524
4525 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004526 Handle<FixedArray> names =
4527 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004528
4529 // Get the property names.
4530 jsproto = obj;
4531 int proto_with_hidden_properties = 0;
4532 for (int i = 0; i < length; i++) {
4533 jsproto->GetLocalPropertyNames(*names,
4534 i == 0 ? 0 : local_property_count[i - 1]);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004535 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004536 proto_with_hidden_properties++;
4537 }
4538 if (i < length - 1) {
4539 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4540 }
4541 }
4542
4543 // Filter out name of hidden propeties object.
4544 if (proto_with_hidden_properties > 0) {
4545 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004546 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004547 names->length() - proto_with_hidden_properties);
4548 int dest_pos = 0;
4549 for (int i = 0; i < total_property_count; i++) {
4550 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004551 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004552 continue;
4553 }
4554 names->set(dest_pos++, name);
4555 }
4556 }
4557
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004558 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004559}
4560
4561
4562// Return the names of the local indexed properties.
4563// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004564RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004565 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004566 ASSERT(args.length() == 1);
4567 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004568 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004569 }
4570 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4571
4572 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004573 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004574 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004575 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004576}
4577
4578
4579// Return information on whether an object has a named or indexed interceptor.
4580// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004581RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004582 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004583 ASSERT(args.length() == 1);
4584 if (!args[0]->IsJSObject()) {
4585 return Smi::FromInt(0);
4586 }
4587 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4588
4589 int result = 0;
4590 if (obj->HasNamedInterceptor()) result |= 2;
4591 if (obj->HasIndexedInterceptor()) result |= 1;
4592
4593 return Smi::FromInt(result);
4594}
4595
4596
4597// Return property names from named interceptor.
4598// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004599RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004600 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004601 ASSERT(args.length() == 1);
4602 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4603
4604 if (obj->HasNamedInterceptor()) {
4605 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4606 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4607 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004608 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004609}
4610
4611
4612// Return element names from indexed interceptor.
4613// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004614RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004615 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004616 ASSERT(args.length() == 1);
4617 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4618
4619 if (obj->HasIndexedInterceptor()) {
4620 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4621 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4622 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004623 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004624}
4625
4626
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004627RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004628 ASSERT_EQ(args.length(), 1);
4629 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004630 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004631 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004632
4633 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004634 // Do access checks before going to the global object.
4635 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004636 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004637 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004638 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4639 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004640 }
4641
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004642 Handle<Object> proto(object->GetPrototype());
4643 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004644 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004645 object = Handle<JSObject>::cast(proto);
4646 }
4647
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004648 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4649 LOCAL_ONLY);
4650 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4651 // property array and since the result is mutable we have to create
4652 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004653 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004654 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004655 for (int i = 0; i < length; i++) {
4656 Object* entry = contents->get(i);
4657 if (entry->IsString()) {
4658 copy->set(i, entry);
4659 } else {
4660 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004661 HandleScope scope(isolate);
4662 Handle<Object> entry_handle(entry, isolate);
4663 Handle<Object> entry_str =
4664 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004665 copy->set(i, *entry_str);
4666 }
4667 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004668 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004669}
4670
4671
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004672RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004673 NoHandleAllocation ha;
4674 ASSERT(args.length() == 1);
4675
4676 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004677 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004678 it.AdvanceToArgumentsFrame();
4679 JavaScriptFrame* frame = it.frame();
4680
4681 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004682 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004683
4684 // Try to convert the key to an index. If successful and within
4685 // index return the the argument from the frame.
4686 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004687 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004688 return frame->GetParameter(index);
4689 }
4690
4691 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004692 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004693 bool exception = false;
4694 Handle<Object> converted =
4695 Execution::ToString(args.at<Object>(0), &exception);
4696 if (exception) return Failure::Exception();
4697 Handle<String> key = Handle<String>::cast(converted);
4698
4699 // Try to convert the string key into an array index.
4700 if (key->AsArrayIndex(&index)) {
4701 if (index < n) {
4702 return frame->GetParameter(index);
4703 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004704 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004705 }
4706 }
4707
4708 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004709 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
4710 if (key->Equals(isolate->heap()->callee_symbol())) {
4711 Object* function = frame->function();
4712 if (function->IsJSFunction() &&
4713 JSFunction::cast(function)->shared()->strict_mode()) {
4714 return isolate->Throw(*isolate->factory()->NewTypeError(
4715 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
4716 }
4717 return function;
4718 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004719
4720 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004721 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004722}
4723
4724
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004725RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004726 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004727
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004728 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004729 Handle<Object> object = args.at<Object>(0);
4730 if (object->IsJSObject()) {
4731 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004732 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004733 MaybeObject* ok = js_object->TransformToFastProperties(0);
4734 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004735 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004736 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004737 return *object;
4738}
4739
4740
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004741RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004742 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004743
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004744 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004745 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004746 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004747 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004748 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004749 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004750 return *object;
4751}
4752
4753
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004754RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004755 NoHandleAllocation ha;
4756 ASSERT(args.length() == 1);
4757
4758 return args[0]->ToBoolean();
4759}
4760
4761
4762// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4763// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004764RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004765 NoHandleAllocation ha;
4766
4767 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004768 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004769 HeapObject* heap_obj = HeapObject::cast(obj);
4770
4771 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004772 if (heap_obj->map()->is_undetectable()) {
4773 return isolate->heap()->undefined_symbol();
4774 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004775
4776 InstanceType instance_type = heap_obj->map()->instance_type();
4777 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004778 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004779 }
4780
4781 switch (instance_type) {
4782 case ODDBALL_TYPE:
4783 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004784 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004785 }
4786 if (heap_obj->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004787 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004788 }
4789 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004790 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004791 case JS_FUNCTION_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004792 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004793 default:
4794 // For any kind of object not handled above, the spec rule for
4795 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004796 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004797 }
4798}
4799
4800
lrn@chromium.org25156de2010-04-06 13:10:27 +00004801static bool AreDigits(const char*s, int from, int to) {
4802 for (int i = from; i < to; i++) {
4803 if (s[i] < '0' || s[i] > '9') return false;
4804 }
4805
4806 return true;
4807}
4808
4809
4810static int ParseDecimalInteger(const char*s, int from, int to) {
4811 ASSERT(to - from < 10); // Overflow is not possible.
4812 ASSERT(from < to);
4813 int d = s[from] - '0';
4814
4815 for (int i = from + 1; i < to; i++) {
4816 d = 10 * d + (s[i] - '0');
4817 }
4818
4819 return d;
4820}
4821
4822
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004823RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004824 NoHandleAllocation ha;
4825 ASSERT(args.length() == 1);
4826 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004827 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004828
4829 // Fast case: short integer or some sorts of junk values.
4830 int len = subject->length();
4831 if (subject->IsSeqAsciiString()) {
4832 if (len == 0) return Smi::FromInt(0);
4833
4834 char const* data = SeqAsciiString::cast(subject)->GetChars();
4835 bool minus = (data[0] == '-');
4836 int start_pos = (minus ? 1 : 0);
4837
4838 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004839 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004840 } else if (data[start_pos] > '9') {
4841 // Fast check for a junk value. A valid string may start from a
4842 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4843 // the 'I' character ('Infinity'). All of that have codes not greater than
4844 // '9' except 'I'.
4845 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004846 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004847 }
4848 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4849 // The maximal/minimal smi has 10 digits. If the string has less digits we
4850 // know it will fit into the smi-data type.
4851 int d = ParseDecimalInteger(data, start_pos, len);
4852 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004853 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004854 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004855 } else if (!subject->HasHashCode() &&
4856 len <= String::kMaxArrayIndexSize &&
4857 (len == 1 || data[0] != '0')) {
4858 // String hash is not calculated yet but all the data are present.
4859 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004860 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004861#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004862 subject->Hash(); // Force hash calculation.
4863 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4864 static_cast<int>(hash));
4865#endif
4866 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004867 }
4868 return Smi::FromInt(d);
4869 }
4870 }
4871
4872 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004873 return isolate->heap()->NumberFromDouble(
4874 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004875}
4876
4877
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004878RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004879 NoHandleAllocation ha;
4880 ASSERT(args.length() == 1);
4881
4882 CONVERT_CHECKED(JSArray, codes, args[0]);
4883 int length = Smi::cast(codes->length())->value();
4884
4885 // Check if the string can be ASCII.
4886 int i;
4887 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004888 Object* element;
4889 { MaybeObject* maybe_element = codes->GetElement(i);
4890 // We probably can't get an exception here, but just in order to enforce
4891 // the checking of inputs in the runtime calls we check here.
4892 if (!maybe_element->ToObject(&element)) return maybe_element;
4893 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004894 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4895 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4896 break;
4897 }
4898
lrn@chromium.org303ada72010-10-27 09:33:13 +00004899 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004900 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004901 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004902 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004903 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004904 }
4905
lrn@chromium.org303ada72010-10-27 09:33:13 +00004906 Object* object = NULL;
4907 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004908 String* result = String::cast(object);
4909 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004910 Object* element;
4911 { MaybeObject* maybe_element = codes->GetElement(i);
4912 if (!maybe_element->ToObject(&element)) return maybe_element;
4913 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004914 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004915 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004916 }
4917 return result;
4918}
4919
4920
4921// kNotEscaped is generated by the following:
4922//
4923// #!/bin/perl
4924// for (my $i = 0; $i < 256; $i++) {
4925// print "\n" if $i % 16 == 0;
4926// my $c = chr($i);
4927// my $escaped = 1;
4928// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4929// print $escaped ? "0, " : "1, ";
4930// }
4931
4932
4933static bool IsNotEscaped(uint16_t character) {
4934 // Only for 8 bit characters, the rest are always escaped (in a different way)
4935 ASSERT(character < 256);
4936 static const char kNotEscaped[256] = {
4937 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4938 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4939 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4940 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4941 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4942 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4943 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4944 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4945 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4946 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4947 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4948 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4949 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4950 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4951 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4952 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4953 };
4954 return kNotEscaped[character] != 0;
4955}
4956
4957
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004958RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004959 const char hex_chars[] = "0123456789ABCDEF";
4960 NoHandleAllocation ha;
4961 ASSERT(args.length() == 1);
4962 CONVERT_CHECKED(String, source, args[0]);
4963
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004964 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004965
4966 int escaped_length = 0;
4967 int length = source->length();
4968 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004969 Access<StringInputBuffer> buffer(
4970 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004971 buffer->Reset(source);
4972 while (buffer->has_more()) {
4973 uint16_t character = buffer->GetNext();
4974 if (character >= 256) {
4975 escaped_length += 6;
4976 } else if (IsNotEscaped(character)) {
4977 escaped_length++;
4978 } else {
4979 escaped_length += 3;
4980 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004981 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004982 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004983 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004984 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004985 return Failure::OutOfMemoryException();
4986 }
4987 }
4988 }
4989 // No length change implies no change. Return original string if no change.
4990 if (escaped_length == length) {
4991 return source;
4992 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004993 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004994 { MaybeObject* maybe_o =
4995 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004996 if (!maybe_o->ToObject(&o)) return maybe_o;
4997 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004998 String* destination = String::cast(o);
4999 int dest_position = 0;
5000
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005001 Access<StringInputBuffer> buffer(
5002 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005003 buffer->Rewind();
5004 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005005 uint16_t chr = buffer->GetNext();
5006 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005007 destination->Set(dest_position, '%');
5008 destination->Set(dest_position+1, 'u');
5009 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5010 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5011 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5012 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005013 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005014 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005015 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005016 dest_position++;
5017 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005018 destination->Set(dest_position, '%');
5019 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5020 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005021 dest_position += 3;
5022 }
5023 }
5024 return destination;
5025}
5026
5027
5028static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5029 static const signed char kHexValue['g'] = {
5030 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5031 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5032 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5033 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5034 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5035 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5036 -1, 10, 11, 12, 13, 14, 15 };
5037
5038 if (character1 > 'f') return -1;
5039 int hi = kHexValue[character1];
5040 if (hi == -1) return -1;
5041 if (character2 > 'f') return -1;
5042 int lo = kHexValue[character2];
5043 if (lo == -1) return -1;
5044 return (hi << 4) + lo;
5045}
5046
5047
ager@chromium.org870a0b62008-11-04 11:43:05 +00005048static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005049 int i,
5050 int length,
5051 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005052 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005053 int32_t hi = 0;
5054 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005055 if (character == '%' &&
5056 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005057 source->Get(i + 1) == 'u' &&
5058 (hi = TwoDigitHex(source->Get(i + 2),
5059 source->Get(i + 3))) != -1 &&
5060 (lo = TwoDigitHex(source->Get(i + 4),
5061 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005062 *step = 6;
5063 return (hi << 8) + lo;
5064 } else if (character == '%' &&
5065 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005066 (lo = TwoDigitHex(source->Get(i + 1),
5067 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005068 *step = 3;
5069 return lo;
5070 } else {
5071 *step = 1;
5072 return character;
5073 }
5074}
5075
5076
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005077RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005078 NoHandleAllocation ha;
5079 ASSERT(args.length() == 1);
5080 CONVERT_CHECKED(String, source, args[0]);
5081
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005082 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005083
5084 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005085 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005086
5087 int unescaped_length = 0;
5088 for (int i = 0; i < length; unescaped_length++) {
5089 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005090 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005091 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005092 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005093 i += step;
5094 }
5095
5096 // No length change implies no change. Return original string if no change.
5097 if (unescaped_length == length)
5098 return source;
5099
lrn@chromium.org303ada72010-10-27 09:33:13 +00005100 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005101 { MaybeObject* maybe_o =
5102 ascii ?
5103 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5104 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005105 if (!maybe_o->ToObject(&o)) return maybe_o;
5106 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005107 String* destination = String::cast(o);
5108
5109 int dest_position = 0;
5110 for (int i = 0; i < length; dest_position++) {
5111 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005112 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005113 i += step;
5114 }
5115 return destination;
5116}
5117
5118
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005119static const unsigned int kQuoteTableLength = 128u;
5120
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005121static const int kJsonQuotesCharactersPerEntry = 8;
5122static const char* const JsonQuotes =
5123 "\\u0000 \\u0001 \\u0002 \\u0003 "
5124 "\\u0004 \\u0005 \\u0006 \\u0007 "
5125 "\\b \\t \\n \\u000b "
5126 "\\f \\r \\u000e \\u000f "
5127 "\\u0010 \\u0011 \\u0012 \\u0013 "
5128 "\\u0014 \\u0015 \\u0016 \\u0017 "
5129 "\\u0018 \\u0019 \\u001a \\u001b "
5130 "\\u001c \\u001d \\u001e \\u001f "
5131 " ! \\\" # "
5132 "$ % & ' "
5133 "( ) * + "
5134 ", - . / "
5135 "0 1 2 3 "
5136 "4 5 6 7 "
5137 "8 9 : ; "
5138 "< = > ? "
5139 "@ A B C "
5140 "D E F G "
5141 "H I J K "
5142 "L M N O "
5143 "P Q R S "
5144 "T U V W "
5145 "X Y Z [ "
5146 "\\\\ ] ^ _ "
5147 "` a b c "
5148 "d e f g "
5149 "h i j k "
5150 "l m n o "
5151 "p q r s "
5152 "t u v w "
5153 "x y z { "
5154 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005155
5156
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005157// For a string that is less than 32k characters it should always be
5158// possible to allocate it in new space.
5159static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5160
5161
5162// Doing JSON quoting cannot make the string more than this many times larger.
5163static const int kJsonQuoteWorstCaseBlowup = 6;
5164
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005165static const int kSpaceForQuotesAndComma = 3;
5166static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005167
5168// Covers the entire ASCII range (all other characters are unchanged by JSON
5169// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005170static const byte JsonQuoteLengths[kQuoteTableLength] = {
5171 6, 6, 6, 6, 6, 6, 6, 6,
5172 2, 2, 2, 6, 2, 2, 6, 6,
5173 6, 6, 6, 6, 6, 6, 6, 6,
5174 6, 6, 6, 6, 6, 6, 6, 6,
5175 1, 1, 2, 1, 1, 1, 1, 1,
5176 1, 1, 1, 1, 1, 1, 1, 1,
5177 1, 1, 1, 1, 1, 1, 1, 1,
5178 1, 1, 1, 1, 1, 1, 1, 1,
5179 1, 1, 1, 1, 1, 1, 1, 1,
5180 1, 1, 1, 1, 1, 1, 1, 1,
5181 1, 1, 1, 1, 1, 1, 1, 1,
5182 1, 1, 1, 1, 2, 1, 1, 1,
5183 1, 1, 1, 1, 1, 1, 1, 1,
5184 1, 1, 1, 1, 1, 1, 1, 1,
5185 1, 1, 1, 1, 1, 1, 1, 1,
5186 1, 1, 1, 1, 1, 1, 1, 1,
5187};
5188
5189
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005190template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005191MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005192
5193
5194template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005195MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5196 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005197}
5198
5199
5200template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005201MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5202 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005203}
5204
5205
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005206template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005207static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5208 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005209 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005210 const Char* read_cursor = characters.start();
5211 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005212 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005213 int quoted_length = kSpaceForQuotes;
5214 while (read_cursor < end) {
5215 Char c = *(read_cursor++);
5216 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5217 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005218 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005219 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005220 }
5221 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005222 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5223 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005224 Object* new_object;
5225 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005226 return new_alloc;
5227 }
5228 StringType* new_string = StringType::cast(new_object);
5229
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005230 Char* write_cursor = reinterpret_cast<Char*>(
5231 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005232 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005233 *(write_cursor++) = '"';
5234
5235 read_cursor = characters.start();
5236 while (read_cursor < end) {
5237 Char c = *(read_cursor++);
5238 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5239 *(write_cursor++) = c;
5240 } else {
5241 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5242 const char* replacement = JsonQuotes +
5243 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5244 for (int i = 0; i < len; i++) {
5245 *write_cursor++ = *replacement++;
5246 }
5247 }
5248 }
5249 *(write_cursor++) = '"';
5250 return new_string;
5251}
5252
5253
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005254template <typename SinkChar, typename SourceChar>
5255static inline SinkChar* WriteQuoteJsonString(
5256 Isolate* isolate,
5257 SinkChar* write_cursor,
5258 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005259 // SinkChar is only char if SourceChar is guaranteed to be char.
5260 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005261 const SourceChar* read_cursor = characters.start();
5262 const SourceChar* end = read_cursor + characters.length();
5263 *(write_cursor++) = '"';
5264 while (read_cursor < end) {
5265 SourceChar c = *(read_cursor++);
5266 if (sizeof(SourceChar) > 1u &&
5267 static_cast<unsigned>(c) >= kQuoteTableLength) {
5268 *(write_cursor++) = static_cast<SinkChar>(c);
5269 } else {
5270 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5271 const char* replacement = JsonQuotes +
5272 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5273 write_cursor[0] = replacement[0];
5274 if (len > 1) {
5275 write_cursor[1] = replacement[1];
5276 if (len > 2) {
5277 ASSERT(len == 6);
5278 write_cursor[2] = replacement[2];
5279 write_cursor[3] = replacement[3];
5280 write_cursor[4] = replacement[4];
5281 write_cursor[5] = replacement[5];
5282 }
5283 }
5284 write_cursor += len;
5285 }
5286 }
5287 *(write_cursor++) = '"';
5288 return write_cursor;
5289}
5290
5291
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005292template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005293static MaybeObject* QuoteJsonString(Isolate* isolate,
5294 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005295 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005296 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005297 int worst_case_length =
5298 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005299 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005300 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005301 }
5302
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005303 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5304 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005305 Object* new_object;
5306 if (!new_alloc->ToObject(&new_object)) {
5307 return new_alloc;
5308 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005309 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005310 // Even if our string is small enough to fit in new space we still have to
5311 // handle it being allocated in old space as may happen in the third
5312 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5313 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005314 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005315 }
5316 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005317 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005318
5319 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5320 Char* write_cursor = reinterpret_cast<Char*>(
5321 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005322 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005323 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5324 write_cursor,
5325 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005326 int final_length = static_cast<int>(
5327 write_cursor - reinterpret_cast<Char*>(
5328 new_string->address() + SeqAsciiString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005329 isolate->heap()->new_space()->
5330 template ShrinkStringAtAllocationBoundary<StringType>(
5331 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005332 return new_string;
5333}
5334
5335
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005336RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005337 NoHandleAllocation ha;
5338 CONVERT_CHECKED(String, str, args[0]);
5339 if (!str->IsFlat()) {
5340 MaybeObject* try_flatten = str->TryFlatten();
5341 Object* flat;
5342 if (!try_flatten->ToObject(&flat)) {
5343 return try_flatten;
5344 }
5345 str = String::cast(flat);
5346 ASSERT(str->IsFlat());
5347 }
5348 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005349 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
5350 str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005351 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005352 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
5353 str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005354 }
5355}
5356
5357
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005358RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005359 NoHandleAllocation ha;
5360 CONVERT_CHECKED(String, str, args[0]);
5361 if (!str->IsFlat()) {
5362 MaybeObject* try_flatten = str->TryFlatten();
5363 Object* flat;
5364 if (!try_flatten->ToObject(&flat)) {
5365 return try_flatten;
5366 }
5367 str = String::cast(flat);
5368 ASSERT(str->IsFlat());
5369 }
5370 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005371 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
5372 str->ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005373 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005374 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
5375 str->ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005376 }
5377}
5378
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005379
5380template <typename Char, typename StringType>
5381static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5382 FixedArray* array,
5383 int worst_case_length) {
5384 int length = array->length();
5385
5386 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5387 worst_case_length);
5388 Object* new_object;
5389 if (!new_alloc->ToObject(&new_object)) {
5390 return new_alloc;
5391 }
5392 if (!isolate->heap()->new_space()->Contains(new_object)) {
5393 // Even if our string is small enough to fit in new space we still have to
5394 // handle it being allocated in old space as may happen in the third
5395 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5396 // CEntryStub::GenerateCore.
5397 return isolate->heap()->undefined_value();
5398 }
5399 AssertNoAllocation no_gc;
5400 StringType* new_string = StringType::cast(new_object);
5401 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5402
5403 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5404 Char* write_cursor = reinterpret_cast<Char*>(
5405 new_string->address() + SeqAsciiString::kHeaderSize);
5406 *(write_cursor++) = '[';
5407 for (int i = 0; i < length; i++) {
5408 if (i != 0) *(write_cursor++) = ',';
5409 String* str = String::cast(array->get(i));
5410 if (str->IsTwoByteRepresentation()) {
5411 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5412 write_cursor,
5413 str->ToUC16Vector());
5414 } else {
5415 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5416 write_cursor,
5417 str->ToAsciiVector());
5418 }
5419 }
5420 *(write_cursor++) = ']';
5421
5422 int final_length = static_cast<int>(
5423 write_cursor - reinterpret_cast<Char*>(
5424 new_string->address() + SeqAsciiString::kHeaderSize));
5425 isolate->heap()->new_space()->
5426 template ShrinkStringAtAllocationBoundary<StringType>(
5427 new_string, final_length);
5428 return new_string;
5429}
5430
5431
5432RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5433 NoHandleAllocation ha;
5434 ASSERT(args.length() == 1);
5435 CONVERT_CHECKED(JSArray, array, args[0]);
5436
5437 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5438 FixedArray* elements = FixedArray::cast(array->elements());
5439 int n = elements->length();
5440 bool ascii = true;
5441 int total_length = 0;
5442
5443 for (int i = 0; i < n; i++) {
5444 Object* elt = elements->get(i);
5445 if (!elt->IsString()) return isolate->heap()->undefined_value();
5446 String* element = String::cast(elt);
5447 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5448 total_length += element->length();
5449 if (ascii && element->IsTwoByteRepresentation()) {
5450 ascii = false;
5451 }
5452 }
5453
5454 int worst_case_length =
5455 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5456 + total_length * kJsonQuoteWorstCaseBlowup;
5457
5458 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5459 return isolate->heap()->undefined_value();
5460 }
5461
5462 if (ascii) {
5463 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5464 elements,
5465 worst_case_length);
5466 } else {
5467 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5468 elements,
5469 worst_case_length);
5470 }
5471}
5472
5473
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005474RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005475 NoHandleAllocation ha;
5476
5477 CONVERT_CHECKED(String, s, args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005478 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005479
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005480 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005481
lrn@chromium.org25156de2010-04-06 13:10:27 +00005482 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005483 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005484 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005485}
5486
5487
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005488RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005489 NoHandleAllocation ha;
5490 CONVERT_CHECKED(String, str, args[0]);
5491
5492 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005493 double value = StringToDouble(isolate->unicode_cache(),
5494 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005495
5496 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005497 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005498}
5499
5500
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005501template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005502MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005503 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005504 String* s,
5505 int length,
5506 int input_string_length,
5507 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005508 // We try this twice, once with the assumption that the result is no longer
5509 // than the input and, if that assumption breaks, again with the exact
5510 // length. This may not be pretty, but it is nicer than what was here before
5511 // and I hereby claim my vaffel-is.
5512 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005513 // Allocate the resulting string.
5514 //
5515 // NOTE: This assumes that the upper/lower case of an ascii
5516 // character is also ascii. This is currently the case, but it
5517 // might break in the future if we implement more context and locale
5518 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005519 Object* o;
5520 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005521 ? isolate->heap()->AllocateRawAsciiString(length)
5522 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005523 if (!maybe_o->ToObject(&o)) return maybe_o;
5524 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005525 String* result = String::cast(o);
5526 bool has_changed_character = false;
5527
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005528 // Convert all characters to upper case, assuming that they will fit
5529 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005530 Access<StringInputBuffer> buffer(
5531 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005532 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005533 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005534 // We can assume that the string is not empty
5535 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005536 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005537 bool has_next = buffer->has_more();
5538 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005539 int char_length = mapping->get(current, next, chars);
5540 if (char_length == 0) {
5541 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005542 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005543 i++;
5544 } else if (char_length == 1) {
5545 // Common case: converting the letter resulted in one character.
5546 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005547 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005548 has_changed_character = true;
5549 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005550 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005551 // We've assumed that the result would be as long as the
5552 // input but here is a character that converts to several
5553 // characters. No matter, we calculate the exact length
5554 // of the result and try the whole thing again.
5555 //
5556 // Note that this leaves room for optimization. We could just
5557 // memcpy what we already have to the result string. Also,
5558 // the result string is the last object allocated we could
5559 // "realloc" it and probably, in the vast majority of cases,
5560 // extend the existing string to be able to hold the full
5561 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005562 int next_length = 0;
5563 if (has_next) {
5564 next_length = mapping->get(next, 0, chars);
5565 if (next_length == 0) next_length = 1;
5566 }
5567 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005568 while (buffer->has_more()) {
5569 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005570 // NOTE: we use 0 as the next character here because, while
5571 // the next character may affect what a character converts to,
5572 // it does not in any case affect the length of what it convert
5573 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005574 int char_length = mapping->get(current, 0, chars);
5575 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005576 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005577 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005578 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005579 return Failure::OutOfMemoryException();
5580 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005581 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005582 // Try again with the real length.
5583 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005584 } else {
5585 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005586 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005587 i++;
5588 }
5589 has_changed_character = true;
5590 }
5591 current = next;
5592 }
5593 if (has_changed_character) {
5594 return result;
5595 } else {
5596 // If we didn't actually change anything in doing the conversion
5597 // we simple return the result and let the converted string
5598 // become garbage; there is no reason to keep two identical strings
5599 // alive.
5600 return s;
5601 }
5602}
5603
5604
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005605namespace {
5606
lrn@chromium.org303ada72010-10-27 09:33:13 +00005607static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5608
5609
5610// Given a word and two range boundaries returns a word with high bit
5611// set in every byte iff the corresponding input byte was strictly in
5612// the range (m, n). All the other bits in the result are cleared.
5613// This function is only useful when it can be inlined and the
5614// boundaries are statically known.
5615// Requires: all bytes in the input word and the boundaries must be
5616// ascii (less than 0x7F).
5617static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5618 // Every byte in an ascii string is less than or equal to 0x7F.
5619 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5620 // Use strict inequalities since in edge cases the function could be
5621 // further simplified.
5622 ASSERT(0 < m && m < n && n < 0x7F);
5623 // Has high bit set in every w byte less than n.
5624 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5625 // Has high bit set in every w byte greater than m.
5626 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5627 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5628}
5629
5630
5631enum AsciiCaseConversion {
5632 ASCII_TO_LOWER,
5633 ASCII_TO_UPPER
5634};
5635
5636
5637template <AsciiCaseConversion dir>
5638struct FastAsciiConverter {
5639 static bool Convert(char* dst, char* src, int length) {
5640#ifdef DEBUG
5641 char* saved_dst = dst;
5642 char* saved_src = src;
5643#endif
5644 // We rely on the distance between upper and lower case letters
5645 // being a known power of 2.
5646 ASSERT('a' - 'A' == (1 << 5));
5647 // Boundaries for the range of input characters than require conversion.
5648 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5649 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5650 bool changed = false;
5651 char* const limit = src + length;
5652#ifdef V8_HOST_CAN_READ_UNALIGNED
5653 // Process the prefix of the input that requires no conversion one
5654 // (machine) word at a time.
5655 while (src <= limit - sizeof(uintptr_t)) {
5656 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5657 if (AsciiRangeMask(w, lo, hi) != 0) {
5658 changed = true;
5659 break;
5660 }
5661 *reinterpret_cast<uintptr_t*>(dst) = w;
5662 src += sizeof(uintptr_t);
5663 dst += sizeof(uintptr_t);
5664 }
5665 // Process the remainder of the input performing conversion when
5666 // required one word at a time.
5667 while (src <= limit - sizeof(uintptr_t)) {
5668 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5669 uintptr_t m = AsciiRangeMask(w, lo, hi);
5670 // The mask has high (7th) bit set in every byte that needs
5671 // conversion and we know that the distance between cases is
5672 // 1 << 5.
5673 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5674 src += sizeof(uintptr_t);
5675 dst += sizeof(uintptr_t);
5676 }
5677#endif
5678 // Process the last few bytes of the input (or the whole input if
5679 // unaligned access is not supported).
5680 while (src < limit) {
5681 char c = *src;
5682 if (lo < c && c < hi) {
5683 c ^= (1 << 5);
5684 changed = true;
5685 }
5686 *dst = c;
5687 ++src;
5688 ++dst;
5689 }
5690#ifdef DEBUG
5691 CheckConvert(saved_dst, saved_src, length, changed);
5692#endif
5693 return changed;
5694 }
5695
5696#ifdef DEBUG
5697 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5698 bool expected_changed = false;
5699 for (int i = 0; i < length; i++) {
5700 if (dst[i] == src[i]) continue;
5701 expected_changed = true;
5702 if (dir == ASCII_TO_LOWER) {
5703 ASSERT('A' <= src[i] && src[i] <= 'Z');
5704 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5705 } else {
5706 ASSERT(dir == ASCII_TO_UPPER);
5707 ASSERT('a' <= src[i] && src[i] <= 'z');
5708 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5709 }
5710 }
5711 ASSERT(expected_changed == changed);
5712 }
5713#endif
5714};
5715
5716
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005717struct ToLowerTraits {
5718 typedef unibrow::ToLowercase UnibrowConverter;
5719
lrn@chromium.org303ada72010-10-27 09:33:13 +00005720 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005721};
5722
5723
5724struct ToUpperTraits {
5725 typedef unibrow::ToUppercase UnibrowConverter;
5726
lrn@chromium.org303ada72010-10-27 09:33:13 +00005727 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005728};
5729
5730} // namespace
5731
5732
5733template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005734MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005735 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005736 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005737 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005738 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005739 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005740 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005741
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005742 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005743 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005744 if (length == 0) return s;
5745
5746 // Simpler handling of ascii strings.
5747 //
5748 // NOTE: This assumes that the upper/lower case of an ascii
5749 // character is also ascii. This is currently the case, but it
5750 // might break in the future if we implement more context and locale
5751 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005752 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005753 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005754 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005755 if (!maybe_o->ToObject(&o)) return maybe_o;
5756 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005757 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005758 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005759 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005760 return has_changed_character ? result : s;
5761 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005762
lrn@chromium.org303ada72010-10-27 09:33:13 +00005763 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005764 { MaybeObject* maybe_answer =
5765 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005766 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5767 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005768 if (answer->IsSmi()) {
5769 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005770 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005771 ConvertCaseHelper(isolate,
5772 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005773 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5774 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005775 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005776 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005777}
5778
5779
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005780RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005781 return ConvertCase<ToLowerTraits>(
5782 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005783}
5784
5785
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005786RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005787 return ConvertCase<ToUpperTraits>(
5788 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005789}
5790
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005791
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005792static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5793 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5794}
5795
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005796
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005797RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005798 NoHandleAllocation ha;
5799 ASSERT(args.length() == 3);
5800
5801 CONVERT_CHECKED(String, s, args[0]);
5802 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5803 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5804
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005805 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005806 int length = s->length();
5807
5808 int left = 0;
5809 if (trimLeft) {
5810 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5811 left++;
5812 }
5813 }
5814
5815 int right = length;
5816 if (trimRight) {
5817 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5818 right--;
5819 }
5820 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005821 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005822}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005823
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005824
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005825void FindAsciiStringIndices(Vector<const char> subject,
5826 char pattern,
5827 ZoneList<int>* indices,
5828 unsigned int limit) {
5829 ASSERT(limit > 0);
5830 // Collect indices of pattern in subject using memchr.
5831 // Stop after finding at most limit values.
5832 const char* subject_start = reinterpret_cast<const char*>(subject.start());
5833 const char* subject_end = subject_start + subject.length();
5834 const char* pos = subject_start;
5835 while (limit > 0) {
5836 pos = reinterpret_cast<const char*>(
5837 memchr(pos, pattern, subject_end - pos));
5838 if (pos == NULL) return;
5839 indices->Add(static_cast<int>(pos - subject_start));
5840 pos++;
5841 limit--;
5842 }
5843}
5844
5845
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005846template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005847void FindStringIndices(Isolate* isolate,
5848 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005849 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005850 ZoneList<int>* indices,
5851 unsigned int limit) {
5852 ASSERT(limit > 0);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005853 // Collect indices of pattern in subject.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005854 // Stop after finding at most limit values.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005855 int pattern_length = pattern.length();
5856 int index = 0;
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005857 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005858 while (limit > 0) {
5859 index = search.Search(subject, index);
5860 if (index < 0) return;
5861 indices->Add(index);
5862 index += pattern_length;
5863 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005864 }
5865}
5866
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005867
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005868RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005869 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005870 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005871 CONVERT_ARG_CHECKED(String, subject, 0);
5872 CONVERT_ARG_CHECKED(String, pattern, 1);
5873 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5874
5875 int subject_length = subject->length();
5876 int pattern_length = pattern->length();
5877 RUNTIME_ASSERT(pattern_length > 0);
5878
5879 // The limit can be very large (0xffffffffu), but since the pattern
5880 // isn't empty, we can never create more parts than ~half the length
5881 // of the subject.
5882
5883 if (!subject->IsFlat()) FlattenString(subject);
5884
5885 static const int kMaxInitialListCapacity = 16;
5886
danno@chromium.org40cb8782011-05-25 07:58:50 +00005887 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005888
5889 // Find (up to limit) indices of separator and end-of-string in subject
5890 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5891 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005892 if (!pattern->IsFlat()) FlattenString(pattern);
5893
5894 // No allocation block.
5895 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005896 AssertNoAllocation nogc;
5897 if (subject->IsAsciiRepresentation()) {
5898 Vector<const char> subject_vector = subject->ToAsciiVector();
5899 if (pattern->IsAsciiRepresentation()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005900 Vector<const char> pattern_vector = pattern->ToAsciiVector();
5901 if (pattern_vector.length() == 1) {
5902 FindAsciiStringIndices(subject_vector,
5903 pattern_vector[0],
5904 &indices,
5905 limit);
5906 } else {
5907 FindStringIndices(isolate,
5908 subject_vector,
5909 pattern_vector,
5910 &indices,
5911 limit);
5912 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005913 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005914 FindStringIndices(isolate,
5915 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005916 pattern->ToUC16Vector(),
5917 &indices,
5918 limit);
5919 }
5920 } else {
5921 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5922 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005923 FindStringIndices(isolate,
5924 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005925 pattern->ToAsciiVector(),
5926 &indices,
5927 limit);
5928 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005929 FindStringIndices(isolate,
5930 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005931 pattern->ToUC16Vector(),
5932 &indices,
5933 limit);
5934 }
5935 }
5936 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005937
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005938 if (static_cast<uint32_t>(indices.length()) < limit) {
5939 indices.Add(subject_length);
5940 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005941
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005942 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005943
5944 // Create JSArray of substrings separated by separator.
5945 int part_count = indices.length();
5946
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005947 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005948 result->set_length(Smi::FromInt(part_count));
5949
5950 ASSERT(result->HasFastElements());
5951
5952 if (part_count == 1 && indices.at(0) == subject_length) {
5953 FixedArray::cast(result->elements())->set(0, *subject);
5954 return *result;
5955 }
5956
5957 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5958 int part_start = 0;
5959 for (int i = 0; i < part_count; i++) {
5960 HandleScope local_loop_handle;
5961 int part_end = indices.at(i);
5962 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00005963 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005964 elements->set(i, *substring);
5965 part_start = part_end + pattern_length;
5966 }
5967
5968 return *result;
5969}
5970
5971
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005972// Copies ascii characters to the given fixed array looking up
5973// one-char strings in the cache. Gives up on the first char that is
5974// not in the cache and fills the remainder with smi zeros. Returns
5975// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005976static int CopyCachedAsciiCharsToArray(Heap* heap,
5977 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005978 FixedArray* elements,
5979 int length) {
5980 AssertNoAllocation nogc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005981 FixedArray* ascii_cache = heap->single_character_string_cache();
5982 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005983 int i;
5984 for (i = 0; i < length; ++i) {
5985 Object* value = ascii_cache->get(chars[i]);
5986 if (value == undefined) break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005987 ASSERT(!heap->InNewSpace(value));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005988 elements->set(i, value, SKIP_WRITE_BARRIER);
5989 }
5990 if (i < length) {
5991 ASSERT(Smi::FromInt(0) == 0);
5992 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5993 }
5994#ifdef DEBUG
5995 for (int j = 0; j < length; ++j) {
5996 Object* element = elements->get(j);
5997 ASSERT(element == Smi::FromInt(0) ||
5998 (element->IsString() && String::cast(element)->LooksValid()));
5999 }
6000#endif
6001 return i;
6002}
6003
6004
6005// Converts a String to JSArray.
6006// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006007RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006008 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006009 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006010 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006011 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006012
6013 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006014 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006015
6016 Handle<FixedArray> elements;
6017 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006018 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006019 { MaybeObject* maybe_obj =
6020 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006021 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6022 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006023 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006024
6025 Vector<const char> chars = s->ToAsciiVector();
6026 // Note, this will initialize all elements (not only the prefix)
6027 // to prevent GC from seeing partially initialized array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006028 int num_copied_from_cache = CopyCachedAsciiCharsToArray(isolate->heap(),
6029 chars.start(),
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006030 *elements,
6031 length);
6032
6033 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006034 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
6035 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006036 }
6037 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006038 elements = isolate->factory()->NewFixedArray(length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006039 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006040 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6041 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006042 }
6043 }
6044
6045#ifdef DEBUG
6046 for (int i = 0; i < length; ++i) {
6047 ASSERT(String::cast(elements->get(i))->length() == 1);
6048 }
6049#endif
6050
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006051 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006052}
6053
6054
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006055RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006056 NoHandleAllocation ha;
6057 ASSERT(args.length() == 1);
6058 CONVERT_CHECKED(String, value, args[0]);
6059 return value->ToObject();
6060}
6061
6062
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006063bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006064 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006065 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006066 return char_length == 0;
6067}
6068
6069
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006070RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006071 NoHandleAllocation ha;
6072 ASSERT(args.length() == 1);
6073
6074 Object* number = args[0];
6075 RUNTIME_ASSERT(number->IsNumber());
6076
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006077 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006078}
6079
6080
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006081RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006082 NoHandleAllocation ha;
6083 ASSERT(args.length() == 1);
6084
6085 Object* number = args[0];
6086 RUNTIME_ASSERT(number->IsNumber());
6087
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006088 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006089}
6090
6091
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006092RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006093 NoHandleAllocation ha;
6094 ASSERT(args.length() == 1);
6095
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006096 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006097
6098 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6099 if (number > 0 && number <= Smi::kMaxValue) {
6100 return Smi::FromInt(static_cast<int>(number));
6101 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006102 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006103}
6104
6105
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006106RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006107 NoHandleAllocation ha;
6108 ASSERT(args.length() == 1);
6109
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006110 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006111
6112 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6113 if (number > 0 && number <= Smi::kMaxValue) {
6114 return Smi::FromInt(static_cast<int>(number));
6115 }
6116
6117 double double_value = DoubleToInteger(number);
6118 // Map both -0 and +0 to +0.
6119 if (double_value == 0) double_value = 0;
6120
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006121 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006122}
6123
6124
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006125RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006126 NoHandleAllocation ha;
6127 ASSERT(args.length() == 1);
6128
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006129 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006130 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006131}
6132
6133
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006134RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006135 NoHandleAllocation ha;
6136 ASSERT(args.length() == 1);
6137
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006138 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006139
6140 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6141 if (number > 0 && number <= Smi::kMaxValue) {
6142 return Smi::FromInt(static_cast<int>(number));
6143 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006144 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006145}
6146
6147
ager@chromium.org870a0b62008-11-04 11:43:05 +00006148// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6149// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006150RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006151 NoHandleAllocation ha;
6152 ASSERT(args.length() == 1);
6153
6154 Object* obj = args[0];
6155 if (obj->IsSmi()) {
6156 return obj;
6157 }
6158 if (obj->IsHeapNumber()) {
6159 double value = HeapNumber::cast(obj)->value();
6160 int int_value = FastD2I(value);
6161 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6162 return Smi::FromInt(int_value);
6163 }
6164 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006165 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006166}
6167
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006168
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006169RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006170 NoHandleAllocation ha;
6171 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006172 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006173}
6174
6175
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006176RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006177 NoHandleAllocation ha;
6178 ASSERT(args.length() == 2);
6179
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006180 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6181 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006182 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006183}
6184
6185
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006186RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006187 NoHandleAllocation ha;
6188 ASSERT(args.length() == 2);
6189
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006190 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6191 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006192 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006193}
6194
6195
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006196RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006197 NoHandleAllocation ha;
6198 ASSERT(args.length() == 2);
6199
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006200 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6201 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006202 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006203}
6204
6205
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006206RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006207 NoHandleAllocation ha;
6208 ASSERT(args.length() == 1);
6209
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006210 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006211 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006212}
6213
6214
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006215RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006216 NoHandleAllocation ha;
6217 ASSERT(args.length() == 0);
6218
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006219 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006220}
6221
6222
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006223RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006224 NoHandleAllocation ha;
6225 ASSERT(args.length() == 2);
6226
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006227 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6228 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006229 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006230}
6231
6232
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006233RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006234 NoHandleAllocation ha;
6235 ASSERT(args.length() == 2);
6236
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006237 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6238 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006239
ager@chromium.org3811b432009-10-28 14:53:37 +00006240 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006241 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006242 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006243}
6244
6245
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006246RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006247 NoHandleAllocation ha;
6248 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006249 CONVERT_CHECKED(String, str1, args[0]);
6250 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006251 isolate->counters()->string_add_runtime()->Increment();
6252 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006253}
6254
6255
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006256template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006257static inline void StringBuilderConcatHelper(String* special,
6258 sinkchar* sink,
6259 FixedArray* fixed_array,
6260 int array_length) {
6261 int position = 0;
6262 for (int i = 0; i < array_length; i++) {
6263 Object* element = fixed_array->get(i);
6264 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006265 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006266 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006267 int pos;
6268 int len;
6269 if (encoded_slice > 0) {
6270 // Position and length encoded in one smi.
6271 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6272 len = StringBuilderSubstringLength::decode(encoded_slice);
6273 } else {
6274 // Position and length encoded in two smis.
6275 Object* obj = fixed_array->get(++i);
6276 ASSERT(obj->IsSmi());
6277 pos = Smi::cast(obj)->value();
6278 len = -encoded_slice;
6279 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006280 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006281 sink + position,
6282 pos,
6283 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006284 position += len;
6285 } else {
6286 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006287 int element_length = string->length();
6288 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006289 position += element_length;
6290 }
6291 }
6292}
6293
6294
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006295RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006296 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006297 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006298 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006299 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006300 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006301 return Failure::OutOfMemoryException();
6302 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006303 int array_length = args.smi_at(1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006304 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006305
6306 // This assumption is used by the slice encoding in one or two smis.
6307 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6308
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006309 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006310 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006311 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006312 }
6313 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006314 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006315 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006316 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006317
6318 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006319 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006320 } else if (array_length == 1) {
6321 Object* first = fixed_array->get(0);
6322 if (first->IsString()) return first;
6323 }
6324
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006325 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006326 int position = 0;
6327 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006328 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006329 Object* elt = fixed_array->get(i);
6330 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006331 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006332 int smi_value = Smi::cast(elt)->value();
6333 int pos;
6334 int len;
6335 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006336 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006337 pos = StringBuilderSubstringPosition::decode(smi_value);
6338 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006339 } else {
6340 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006341 len = -smi_value;
6342 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006343 i++;
6344 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006345 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006346 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006347 Object* next_smi = fixed_array->get(i);
6348 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006349 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006350 }
6351 pos = Smi::cast(next_smi)->value();
6352 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006353 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006354 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006355 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006356 ASSERT(pos >= 0);
6357 ASSERT(len >= 0);
6358 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006359 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006360 }
6361 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006362 } else if (elt->IsString()) {
6363 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006364 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006365 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006366 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006367 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006368 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006369 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006370 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006371 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006372 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006373 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006374 return Failure::OutOfMemoryException();
6375 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006376 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006377 }
6378
6379 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006380 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006381
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006382 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006383 { MaybeObject* maybe_object =
6384 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006385 if (!maybe_object->ToObject(&object)) return maybe_object;
6386 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006387 SeqAsciiString* answer = SeqAsciiString::cast(object);
6388 StringBuilderConcatHelper(special,
6389 answer->GetChars(),
6390 fixed_array,
6391 array_length);
6392 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006393 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006394 { MaybeObject* maybe_object =
6395 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006396 if (!maybe_object->ToObject(&object)) return maybe_object;
6397 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006398 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6399 StringBuilderConcatHelper(special,
6400 answer->GetChars(),
6401 fixed_array,
6402 array_length);
6403 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006404 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006405}
6406
6407
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006408RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006409 NoHandleAllocation ha;
6410 ASSERT(args.length() == 3);
6411 CONVERT_CHECKED(JSArray, array, args[0]);
6412 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006413 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006414 return Failure::OutOfMemoryException();
6415 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006416 int array_length = args.smi_at(1);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006417 CONVERT_CHECKED(String, separator, args[2]);
6418
6419 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006420 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006421 }
6422 FixedArray* fixed_array = FixedArray::cast(array->elements());
6423 if (fixed_array->length() < array_length) {
6424 array_length = fixed_array->length();
6425 }
6426
6427 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006428 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006429 } else if (array_length == 1) {
6430 Object* first = fixed_array->get(0);
6431 if (first->IsString()) return first;
6432 }
6433
6434 int separator_length = separator->length();
6435 int max_nof_separators =
6436 (String::kMaxLength + separator_length - 1) / separator_length;
6437 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006438 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006439 return Failure::OutOfMemoryException();
6440 }
6441 int length = (array_length - 1) * separator_length;
6442 for (int i = 0; i < array_length; i++) {
6443 Object* element_obj = fixed_array->get(i);
6444 if (!element_obj->IsString()) {
6445 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006446 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006447 }
6448 String* element = String::cast(element_obj);
6449 int increment = element->length();
6450 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006451 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006452 return Failure::OutOfMemoryException();
6453 }
6454 length += increment;
6455 }
6456
6457 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006458 { MaybeObject* maybe_object =
6459 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006460 if (!maybe_object->ToObject(&object)) return maybe_object;
6461 }
6462 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6463
6464 uc16* sink = answer->GetChars();
6465#ifdef DEBUG
6466 uc16* end = sink + length;
6467#endif
6468
6469 String* first = String::cast(fixed_array->get(0));
6470 int first_length = first->length();
6471 String::WriteToFlat(first, sink, 0, first_length);
6472 sink += first_length;
6473
6474 for (int i = 1; i < array_length; i++) {
6475 ASSERT(sink + separator_length <= end);
6476 String::WriteToFlat(separator, sink, 0, separator_length);
6477 sink += separator_length;
6478
6479 String* element = String::cast(fixed_array->get(i));
6480 int element_length = element->length();
6481 ASSERT(sink + element_length <= end);
6482 String::WriteToFlat(element, sink, 0, element_length);
6483 sink += element_length;
6484 }
6485 ASSERT(sink == end);
6486
6487 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6488 return answer;
6489}
6490
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006491template <typename Char>
6492static void JoinSparseArrayWithSeparator(FixedArray* elements,
6493 int elements_length,
6494 uint32_t array_length,
6495 String* separator,
6496 Vector<Char> buffer) {
6497 int previous_separator_position = 0;
6498 int separator_length = separator->length();
6499 int cursor = 0;
6500 for (int i = 0; i < elements_length; i += 2) {
6501 int position = NumberToInt32(elements->get(i));
6502 String* string = String::cast(elements->get(i + 1));
6503 int string_length = string->length();
6504 if (string->length() > 0) {
6505 while (previous_separator_position < position) {
6506 String::WriteToFlat<Char>(separator, &buffer[cursor],
6507 0, separator_length);
6508 cursor += separator_length;
6509 previous_separator_position++;
6510 }
6511 String::WriteToFlat<Char>(string, &buffer[cursor],
6512 0, string_length);
6513 cursor += string->length();
6514 }
6515 }
6516 if (separator_length > 0) {
6517 // Array length must be representable as a signed 32-bit number,
6518 // otherwise the total string length would have been too large.
6519 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6520 int last_array_index = static_cast<int>(array_length - 1);
6521 while (previous_separator_position < last_array_index) {
6522 String::WriteToFlat<Char>(separator, &buffer[cursor],
6523 0, separator_length);
6524 cursor += separator_length;
6525 previous_separator_position++;
6526 }
6527 }
6528 ASSERT(cursor <= buffer.length());
6529}
6530
6531
6532RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6533 NoHandleAllocation ha;
6534 ASSERT(args.length() == 3);
6535 CONVERT_CHECKED(JSArray, elements_array, args[0]);
6536 RUNTIME_ASSERT(elements_array->HasFastElements());
6537 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6538 CONVERT_CHECKED(String, separator, args[2]);
6539 // elements_array is fast-mode JSarray of alternating positions
6540 // (increasing order) and strings.
6541 // array_length is length of original array (used to add separators);
6542 // separator is string to put between elements. Assumed to be non-empty.
6543
6544 // Find total length of join result.
6545 int string_length = 0;
6546 bool is_ascii = true;
6547 int max_string_length = SeqAsciiString::kMaxLength;
6548 bool overflow = false;
6549 CONVERT_NUMBER_CHECKED(int, elements_length,
6550 Int32, elements_array->length());
6551 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6552 FixedArray* elements = FixedArray::cast(elements_array->elements());
6553 for (int i = 0; i < elements_length; i += 2) {
6554 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6555 CONVERT_CHECKED(String, string, elements->get(i + 1));
6556 int length = string->length();
6557 if (is_ascii && !string->IsAsciiRepresentation()) {
6558 is_ascii = false;
6559 max_string_length = SeqTwoByteString::kMaxLength;
6560 }
6561 if (length > max_string_length ||
6562 max_string_length - length < string_length) {
6563 overflow = true;
6564 break;
6565 }
6566 string_length += length;
6567 }
6568 int separator_length = separator->length();
6569 if (!overflow && separator_length > 0) {
6570 if (array_length <= 0x7fffffffu) {
6571 int separator_count = static_cast<int>(array_length) - 1;
6572 int remaining_length = max_string_length - string_length;
6573 if ((remaining_length / separator_length) >= separator_count) {
6574 string_length += separator_length * (array_length - 1);
6575 } else {
6576 // Not room for the separators within the maximal string length.
6577 overflow = true;
6578 }
6579 } else {
6580 // Nonempty separator and at least 2^31-1 separators necessary
6581 // means that the string is too large to create.
6582 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6583 overflow = true;
6584 }
6585 }
6586 if (overflow) {
6587 // Throw OutOfMemory exception for creating too large a string.
6588 V8::FatalProcessOutOfMemory("Array join result too large.");
6589 }
6590
6591 if (is_ascii) {
6592 MaybeObject* result_allocation =
6593 isolate->heap()->AllocateRawAsciiString(string_length);
6594 if (result_allocation->IsFailure()) return result_allocation;
6595 SeqAsciiString* result_string =
6596 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6597 JoinSparseArrayWithSeparator<char>(elements,
6598 elements_length,
6599 array_length,
6600 separator,
6601 Vector<char>(result_string->GetChars(),
6602 string_length));
6603 return result_string;
6604 } else {
6605 MaybeObject* result_allocation =
6606 isolate->heap()->AllocateRawTwoByteString(string_length);
6607 if (result_allocation->IsFailure()) return result_allocation;
6608 SeqTwoByteString* result_string =
6609 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6610 JoinSparseArrayWithSeparator<uc16>(elements,
6611 elements_length,
6612 array_length,
6613 separator,
6614 Vector<uc16>(result_string->GetChars(),
6615 string_length));
6616 return result_string;
6617 }
6618}
6619
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006620
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006621RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006622 NoHandleAllocation ha;
6623 ASSERT(args.length() == 2);
6624
6625 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6626 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006627 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006628}
6629
6630
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006631RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006632 NoHandleAllocation ha;
6633 ASSERT(args.length() == 2);
6634
6635 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6636 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006637 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006638}
6639
6640
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006641RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006642 NoHandleAllocation ha;
6643 ASSERT(args.length() == 2);
6644
6645 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6646 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006647 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006648}
6649
6650
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006651RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006652 NoHandleAllocation ha;
6653 ASSERT(args.length() == 1);
6654
6655 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006656 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006657}
6658
6659
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006660RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006661 NoHandleAllocation ha;
6662 ASSERT(args.length() == 2);
6663
6664 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6665 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006666 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006667}
6668
6669
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006670RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006671 NoHandleAllocation ha;
6672 ASSERT(args.length() == 2);
6673
6674 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6675 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006676 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006677}
6678
6679
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006680RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006681 NoHandleAllocation ha;
6682 ASSERT(args.length() == 2);
6683
6684 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6685 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006686 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006687}
6688
6689
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006690RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006691 NoHandleAllocation ha;
6692 ASSERT(args.length() == 2);
6693
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006694 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6695 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006696 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6697 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6698 if (x == y) return Smi::FromInt(EQUAL);
6699 Object* result;
6700 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6701 result = Smi::FromInt(EQUAL);
6702 } else {
6703 result = Smi::FromInt(NOT_EQUAL);
6704 }
6705 return result;
6706}
6707
6708
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006709RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006710 NoHandleAllocation ha;
6711 ASSERT(args.length() == 2);
6712
6713 CONVERT_CHECKED(String, x, args[0]);
6714 CONVERT_CHECKED(String, y, args[1]);
6715
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006716 bool not_equal = !x->Equals(y);
6717 // This is slightly convoluted because the value that signifies
6718 // equality is 0 and inequality is 1 so we have to negate the result
6719 // from String::Equals.
6720 ASSERT(not_equal == 0 || not_equal == 1);
6721 STATIC_CHECK(EQUAL == 0);
6722 STATIC_CHECK(NOT_EQUAL == 1);
6723 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006724}
6725
6726
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006727RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006728 NoHandleAllocation ha;
6729 ASSERT(args.length() == 3);
6730
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006731 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6732 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006733 if (isnan(x) || isnan(y)) return args[2];
6734 if (x == y) return Smi::FromInt(EQUAL);
6735 if (isless(x, y)) return Smi::FromInt(LESS);
6736 return Smi::FromInt(GREATER);
6737}
6738
6739
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006740// Compare two Smis as if they were converted to strings and then
6741// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006742RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006743 NoHandleAllocation ha;
6744 ASSERT(args.length() == 2);
6745
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006746 // Extract the integer values from the Smis.
6747 CONVERT_CHECKED(Smi, x, args[0]);
6748 CONVERT_CHECKED(Smi, y, args[1]);
6749 int x_value = x->value();
6750 int y_value = y->value();
6751
6752 // If the integers are equal so are the string representations.
6753 if (x_value == y_value) return Smi::FromInt(EQUAL);
6754
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006755 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006756 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006757 if (x_value == 0 || y_value == 0)
6758 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006759
ager@chromium.org32912102009-01-16 10:38:43 +00006760 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006761 // smallest because the char code of '-' is less than the char code
6762 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006763
6764 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
6765 // architectures using 32-bit Smis.
6766 uint32_t x_scaled = x_value;
6767 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006768 if (x_value < 0 || y_value < 0) {
6769 if (y_value >= 0) return Smi::FromInt(LESS);
6770 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006771 x_scaled = -x_value;
6772 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006773 }
6774
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006775 static const uint32_t kPowersOf10[] = {
6776 1, 10, 100, 1000, 10*1000, 100*1000,
6777 1000*1000, 10*1000*1000, 100*1000*1000,
6778 1000*1000*1000
6779 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006780
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006781 // If the integers have the same number of decimal digits they can be
6782 // compared directly as the numeric order is the same as the
6783 // lexicographic order. If one integer has fewer digits, it is scaled
6784 // by some power of 10 to have the same number of digits as the longer
6785 // integer. If the scaled integers are equal it means the shorter
6786 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006787
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006788 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
6789 int x_log2 = IntegerLog2(x_scaled);
6790 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
6791 x_log10 -= x_scaled < kPowersOf10[x_log10];
6792
6793 int y_log2 = IntegerLog2(y_scaled);
6794 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
6795 y_log10 -= y_scaled < kPowersOf10[y_log10];
6796
6797 int tie = EQUAL;
6798
6799 if (x_log10 < y_log10) {
6800 // X has fewer digits. We would like to simply scale up X but that
6801 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
6802 // be scaled up to 9_000_000_000. So we scale up by the next
6803 // smallest power and scale down Y to drop one digit. It is OK to
6804 // drop one digit from the longer integer since the final digit is
6805 // past the length of the shorter integer.
6806 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
6807 y_scaled /= 10;
6808 tie = LESS;
6809 } else if (y_log10 < x_log10) {
6810 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
6811 x_scaled /= 10;
6812 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006813 }
6814
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006815 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
6816 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
6817 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006818}
6819
6820
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006821static Object* StringInputBufferCompare(RuntimeState* state,
6822 String* x,
6823 String* y) {
6824 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
6825 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006826 bufx.Reset(x);
6827 bufy.Reset(y);
6828 while (bufx.has_more() && bufy.has_more()) {
6829 int d = bufx.GetNext() - bufy.GetNext();
6830 if (d < 0) return Smi::FromInt(LESS);
6831 else if (d > 0) return Smi::FromInt(GREATER);
6832 }
6833
6834 // x is (non-trivial) prefix of y:
6835 if (bufy.has_more()) return Smi::FromInt(LESS);
6836 // y is prefix of x:
6837 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6838}
6839
6840
6841static Object* FlatStringCompare(String* x, String* y) {
6842 ASSERT(x->IsFlat());
6843 ASSERT(y->IsFlat());
6844 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6845 int prefix_length = x->length();
6846 if (y->length() < prefix_length) {
6847 prefix_length = y->length();
6848 equal_prefix_result = Smi::FromInt(GREATER);
6849 } else if (y->length() > prefix_length) {
6850 equal_prefix_result = Smi::FromInt(LESS);
6851 }
6852 int r;
6853 if (x->IsAsciiRepresentation()) {
6854 Vector<const char> x_chars = x->ToAsciiVector();
6855 if (y->IsAsciiRepresentation()) {
6856 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006857 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006858 } else {
6859 Vector<const uc16> y_chars = y->ToUC16Vector();
6860 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6861 }
6862 } else {
6863 Vector<const uc16> x_chars = x->ToUC16Vector();
6864 if (y->IsAsciiRepresentation()) {
6865 Vector<const char> y_chars = y->ToAsciiVector();
6866 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6867 } else {
6868 Vector<const uc16> y_chars = y->ToUC16Vector();
6869 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6870 }
6871 }
6872 Object* result;
6873 if (r == 0) {
6874 result = equal_prefix_result;
6875 } else {
6876 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6877 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006878 ASSERT(result ==
6879 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006880 return result;
6881}
6882
6883
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006884RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006885 NoHandleAllocation ha;
6886 ASSERT(args.length() == 2);
6887
6888 CONVERT_CHECKED(String, x, args[0]);
6889 CONVERT_CHECKED(String, y, args[1]);
6890
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006891 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006892
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006893 // A few fast case tests before we flatten.
6894 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006895 if (y->length() == 0) {
6896 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006897 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006898 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006899 return Smi::FromInt(LESS);
6900 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006901
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006902 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006903 if (d < 0) return Smi::FromInt(LESS);
6904 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006905
lrn@chromium.org303ada72010-10-27 09:33:13 +00006906 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006907 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006908 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6909 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006910 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006911 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6912 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006913
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006914 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006915 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006916}
6917
6918
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006919RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006920 NoHandleAllocation ha;
6921 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006922 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006923
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006924 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006925 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006926}
6927
6928
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006929RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006930 NoHandleAllocation ha;
6931 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006932 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006933
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006934 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006935 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006936}
6937
6938
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006939RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006940 NoHandleAllocation ha;
6941 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006942 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006943
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006944 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006945 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006946}
6947
6948
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006949static const double kPiDividedBy4 = 0.78539816339744830962;
6950
6951
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006952RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006953 NoHandleAllocation ha;
6954 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006955 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006956
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006957 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6958 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006959 double result;
6960 if (isinf(x) && isinf(y)) {
6961 // Make sure that the result in case of two infinite arguments
6962 // is a multiple of Pi / 4. The sign of the result is determined
6963 // by the first argument (x) and the sign of the second argument
6964 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006965 int multiplier = (x < 0) ? -1 : 1;
6966 if (y < 0) multiplier *= 3;
6967 result = multiplier * kPiDividedBy4;
6968 } else {
6969 result = atan2(x, y);
6970 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006971 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006972}
6973
6974
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006975RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006976 NoHandleAllocation ha;
6977 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006978 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006979
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006980 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006981 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006982}
6983
6984
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006985RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006986 NoHandleAllocation ha;
6987 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006988 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006989
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006990 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006991 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006992}
6993
6994
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006995RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006996 NoHandleAllocation ha;
6997 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006998 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006999
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007000 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007001 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007002}
7003
7004
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007005RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007006 NoHandleAllocation ha;
7007 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007008 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007009
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007010 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007011 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007012}
7013
7014
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007015RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007016 NoHandleAllocation ha;
7017 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007018 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007019
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007020 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007021 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007022}
7023
7024
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007025RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007026 NoHandleAllocation ha;
7027 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007028 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007029
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007030 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007031
7032 // If the second argument is a smi, it is much faster to call the
7033 // custom powi() function than the generic pow().
7034 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007035 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007036 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007037 }
7038
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007039 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007040 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007041}
7042
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007043// Fast version of Math.pow if we know that y is not an integer and
7044// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007045RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007046 NoHandleAllocation ha;
7047 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007048 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7049 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007050 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007051 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007052 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007053 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007054 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007055 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007056 }
7057}
7058
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007059
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007060RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007061 NoHandleAllocation ha;
7062 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007063 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007064
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007065 if (!args[0]->IsHeapNumber()) {
7066 // Must be smi. Return the argument unchanged for all the other types
7067 // to make fuzz-natives test happy.
7068 return args[0];
7069 }
7070
7071 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7072
7073 double value = number->value();
7074 int exponent = number->get_exponent();
7075 int sign = number->get_sign();
7076
danno@chromium.org160a7b02011-04-18 15:51:38 +00007077 if (exponent < -1) {
7078 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7079 if (sign) return isolate->heap()->minus_zero_value();
7080 return Smi::FromInt(0);
7081 }
7082
7083 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7084 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
7085 // agument holds for 32-bit smis).
7086 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007087 return Smi::FromInt(static_cast<int>(value + 0.5));
7088 }
7089
7090 // If the magnitude is big enough, there's no place for fraction part. If we
7091 // try to add 0.5 to this number, 1.0 will be added instead.
7092 if (exponent >= 52) {
7093 return number;
7094 }
7095
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007096 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007097
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007098 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007099 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007100}
7101
7102
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007103RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007104 NoHandleAllocation ha;
7105 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007106 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007107
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007108 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007109 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007110}
7111
7112
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007113RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007114 NoHandleAllocation ha;
7115 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007116 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007117
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007118 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007119 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007120}
7121
7122
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007123RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007124 NoHandleAllocation ha;
7125 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007126 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007127
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007128 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007129 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007130}
7131
7132
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007133static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007134 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7135 181, 212, 243, 273, 304, 334};
7136 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7137 182, 213, 244, 274, 305, 335};
7138
7139 year += month / 12;
7140 month %= 12;
7141 if (month < 0) {
7142 year--;
7143 month += 12;
7144 }
7145
7146 ASSERT(month >= 0);
7147 ASSERT(month < 12);
7148
7149 // year_delta is an arbitrary number such that:
7150 // a) year_delta = -1 (mod 400)
7151 // b) year + year_delta > 0 for years in the range defined by
7152 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7153 // Jan 1 1970. This is required so that we don't run into integer
7154 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007155 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007156 // operations.
7157 static const int year_delta = 399999;
7158 static const int base_day = 365 * (1970 + year_delta) +
7159 (1970 + year_delta) / 4 -
7160 (1970 + year_delta) / 100 +
7161 (1970 + year_delta) / 400;
7162
7163 int year1 = year + year_delta;
7164 int day_from_year = 365 * year1 +
7165 year1 / 4 -
7166 year1 / 100 +
7167 year1 / 400 -
7168 base_day;
7169
7170 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007171 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007172 }
7173
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007174 return day_from_year + day_from_month_leap[month] + day - 1;
7175}
7176
7177
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007178RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007179 NoHandleAllocation ha;
7180 ASSERT(args.length() == 3);
7181
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007182 CONVERT_SMI_ARG_CHECKED(year, 0);
7183 CONVERT_SMI_ARG_CHECKED(month, 1);
7184 CONVERT_SMI_ARG_CHECKED(date, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007185
7186 return Smi::FromInt(MakeDay(year, month, date));
7187}
7188
7189
7190static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7191static const int kDaysIn4Years = 4 * 365 + 1;
7192static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7193static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7194static const int kDays1970to2000 = 30 * 365 + 7;
7195static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7196 kDays1970to2000;
7197static const int kYearsOffset = 400000;
7198
7199static const char kDayInYear[] = {
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, 29, 30, 31,
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,
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, 31,
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,
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, 31,
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,
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, 31,
7216 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7217 22, 23, 24, 25, 26, 27, 28, 29, 30,
7218 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7219 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7220 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7221 22, 23, 24, 25, 26, 27, 28, 29, 30,
7222 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7223 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7224
7225 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7226 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7227 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7228 22, 23, 24, 25, 26, 27, 28,
7229 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7230 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7231 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7232 22, 23, 24, 25, 26, 27, 28, 29, 30,
7233 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7234 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7235 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7236 22, 23, 24, 25, 26, 27, 28, 29, 30,
7237 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7238 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7239 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7240 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7241 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7242 22, 23, 24, 25, 26, 27, 28, 29, 30,
7243 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7244 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7245 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7246 22, 23, 24, 25, 26, 27, 28, 29, 30,
7247 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7248 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7249
7250 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7251 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7252 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7253 22, 23, 24, 25, 26, 27, 28, 29,
7254 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7255 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7256 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7257 22, 23, 24, 25, 26, 27, 28, 29, 30,
7258 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7259 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7260 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7261 22, 23, 24, 25, 26, 27, 28, 29, 30,
7262 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7263 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7264 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7265 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7266 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7267 22, 23, 24, 25, 26, 27, 28, 29, 30,
7268 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7269 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7270 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7271 22, 23, 24, 25, 26, 27, 28, 29, 30,
7272 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7273 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7274
7275 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7276 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7277 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7278 22, 23, 24, 25, 26, 27, 28,
7279 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7280 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7281 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7282 22, 23, 24, 25, 26, 27, 28, 29, 30,
7283 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7284 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7285 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7286 22, 23, 24, 25, 26, 27, 28, 29, 30,
7287 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7288 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7289 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7290 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7291 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7292 22, 23, 24, 25, 26, 27, 28, 29, 30,
7293 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7294 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7295 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7296 22, 23, 24, 25, 26, 27, 28, 29, 30,
7297 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7298 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7299
7300static const char kMonthInYear[] = {
7301 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,
7302 0, 0, 0, 0, 0, 0,
7303 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,
7304 1, 1, 1,
7305 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,
7306 2, 2, 2, 2, 2, 2,
7307 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,
7308 3, 3, 3, 3, 3,
7309 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,
7310 4, 4, 4, 4, 4, 4,
7311 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,
7312 5, 5, 5, 5, 5,
7313 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,
7314 6, 6, 6, 6, 6, 6,
7315 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,
7316 7, 7, 7, 7, 7, 7,
7317 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,
7318 8, 8, 8, 8, 8,
7319 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,
7320 9, 9, 9, 9, 9, 9,
7321 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7322 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7323 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7324 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7325
7326 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,
7327 0, 0, 0, 0, 0, 0,
7328 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,
7329 1, 1, 1,
7330 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,
7331 2, 2, 2, 2, 2, 2,
7332 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,
7333 3, 3, 3, 3, 3,
7334 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,
7335 4, 4, 4, 4, 4, 4,
7336 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,
7337 5, 5, 5, 5, 5,
7338 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,
7339 6, 6, 6, 6, 6, 6,
7340 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,
7341 7, 7, 7, 7, 7, 7,
7342 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,
7343 8, 8, 8, 8, 8,
7344 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,
7345 9, 9, 9, 9, 9, 9,
7346 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7347 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7348 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7349 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7350
7351 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,
7352 0, 0, 0, 0, 0, 0,
7353 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,
7354 1, 1, 1, 1,
7355 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,
7356 2, 2, 2, 2, 2, 2,
7357 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,
7358 3, 3, 3, 3, 3,
7359 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,
7360 4, 4, 4, 4, 4, 4,
7361 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,
7362 5, 5, 5, 5, 5,
7363 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,
7364 6, 6, 6, 6, 6, 6,
7365 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,
7366 7, 7, 7, 7, 7, 7,
7367 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,
7368 8, 8, 8, 8, 8,
7369 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,
7370 9, 9, 9, 9, 9, 9,
7371 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7372 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7373 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7374 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7375
7376 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,
7377 0, 0, 0, 0, 0, 0,
7378 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,
7379 1, 1, 1,
7380 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,
7381 2, 2, 2, 2, 2, 2,
7382 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,
7383 3, 3, 3, 3, 3,
7384 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,
7385 4, 4, 4, 4, 4, 4,
7386 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,
7387 5, 5, 5, 5, 5,
7388 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,
7389 6, 6, 6, 6, 6, 6,
7390 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,
7391 7, 7, 7, 7, 7, 7,
7392 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,
7393 8, 8, 8, 8, 8,
7394 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,
7395 9, 9, 9, 9, 9, 9,
7396 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7397 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7398 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7399 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7400
7401
7402// This function works for dates from 1970 to 2099.
7403static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007404 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007405#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007406 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007407#endif
7408
7409 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7410 date %= kDaysIn4Years;
7411
7412 month = kMonthInYear[date];
7413 day = kDayInYear[date];
7414
7415 ASSERT(MakeDay(year, month, day) == save_date);
7416}
7417
7418
7419static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007420 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007421#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007422 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007423#endif
7424
7425 date += kDaysOffset;
7426 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7427 date %= kDaysIn400Years;
7428
7429 ASSERT(MakeDay(year, 0, 1) + date == save_date);
7430
7431 date--;
7432 int yd1 = date / kDaysIn100Years;
7433 date %= kDaysIn100Years;
7434 year += 100 * yd1;
7435
7436 date++;
7437 int yd2 = date / kDaysIn4Years;
7438 date %= kDaysIn4Years;
7439 year += 4 * yd2;
7440
7441 date--;
7442 int yd3 = date / 365;
7443 date %= 365;
7444 year += yd3;
7445
7446 bool is_leap = (!yd1 || yd2) && !yd3;
7447
7448 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007449 ASSERT(is_leap || (date >= 0));
7450 ASSERT((date < 365) || (is_leap && (date < 366)));
7451 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
7452 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
7453 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007454
7455 if (is_leap) {
7456 day = kDayInYear[2*365 + 1 + date];
7457 month = kMonthInYear[2*365 + 1 + date];
7458 } else {
7459 day = kDayInYear[date];
7460 month = kMonthInYear[date];
7461 }
7462
7463 ASSERT(MakeDay(year, month, day) == save_date);
7464}
7465
7466
7467static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007468 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007469 if (date >= 0 && date < 32 * kDaysIn4Years) {
7470 DateYMDFromTimeAfter1970(date, year, month, day);
7471 } else {
7472 DateYMDFromTimeSlow(date, year, month, day);
7473 }
7474}
7475
7476
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007477RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007478 NoHandleAllocation ha;
7479 ASSERT(args.length() == 2);
7480
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007481 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007482 CONVERT_CHECKED(JSArray, res_array, args[1]);
7483
7484 int year, month, day;
7485 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7486
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007487 RUNTIME_ASSERT(res_array->elements()->map() ==
7488 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007489 FixedArray* elms = FixedArray::cast(res_array->elements());
7490 RUNTIME_ASSERT(elms->length() == 3);
7491
7492 elms->set(0, Smi::FromInt(year));
7493 elms->set(1, Smi::FromInt(month));
7494 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007495
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007496 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007497}
7498
7499
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007500RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007501 HandleScope scope(isolate);
7502 ASSERT(args.length() == 3);
7503
7504 Handle<JSFunction> callee = args.at<JSFunction>(0);
7505 Object** parameters = reinterpret_cast<Object**>(args[1]);
7506 const int argument_count = Smi::cast(args[2])->value();
7507
7508 Handle<JSObject> result =
7509 isolate->factory()->NewArgumentsObject(callee, argument_count);
7510 // Allocate the elements if needed.
7511 int parameter_count = callee->shared()->formal_parameter_count();
7512 if (argument_count > 0) {
7513 if (parameter_count > 0) {
7514 int mapped_count = Min(argument_count, parameter_count);
7515 Handle<FixedArray> parameter_map =
7516 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7517 parameter_map->set_map(
7518 isolate->heap()->non_strict_arguments_elements_map());
7519
7520 Handle<Map> old_map(result->map());
7521 Handle<Map> new_map =
7522 isolate->factory()->CopyMapDropTransitions(old_map);
7523 new_map->set_elements_kind(JSObject::NON_STRICT_ARGUMENTS_ELEMENTS);
7524
7525 result->set_map(*new_map);
7526 result->set_elements(*parameter_map);
7527
7528 // Store the context and the arguments array at the beginning of the
7529 // parameter map.
7530 Handle<Context> context(isolate->context());
7531 Handle<FixedArray> arguments =
7532 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7533 parameter_map->set(0, *context);
7534 parameter_map->set(1, *arguments);
7535
7536 // Loop over the actual parameters backwards.
7537 int index = argument_count - 1;
7538 while (index >= mapped_count) {
7539 // These go directly in the arguments array and have no
7540 // corresponding slot in the parameter map.
7541 arguments->set(index, *(parameters - index - 1));
7542 --index;
7543 }
7544
7545 ScopeInfo<> scope_info(callee->shared()->scope_info());
7546 while (index >= 0) {
7547 // Detect duplicate names to the right in the parameter list.
7548 Handle<String> name = scope_info.parameter_name(index);
7549 int context_slot_count = scope_info.number_of_context_slots();
7550 bool duplicate = false;
7551 for (int j = index + 1; j < parameter_count; ++j) {
7552 if (scope_info.parameter_name(j).is_identical_to(name)) {
7553 duplicate = true;
7554 break;
7555 }
7556 }
7557
7558 if (duplicate) {
7559 // This goes directly in the arguments array with a hole in the
7560 // parameter map.
7561 arguments->set(index, *(parameters - index - 1));
7562 parameter_map->set_the_hole(index + 2);
7563 } else {
7564 // The context index goes in the parameter map with a hole in the
7565 // arguments array.
7566 int context_index = -1;
7567 for (int j = Context::MIN_CONTEXT_SLOTS;
7568 j < context_slot_count;
7569 ++j) {
7570 if (scope_info.context_slot_name(j).is_identical_to(name)) {
7571 context_index = j;
7572 break;
7573 }
7574 }
7575 ASSERT(context_index >= 0);
7576 arguments->set_the_hole(index);
7577 parameter_map->set(index + 2, Smi::FromInt(context_index));
7578 }
7579
7580 --index;
7581 }
7582 } else {
7583 // If there is no aliasing, the arguments object elements are not
7584 // special in any way.
7585 Handle<FixedArray> elements =
7586 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7587 result->set_elements(*elements);
7588 for (int i = 0; i < argument_count; ++i) {
7589 elements->set(i, *(parameters - i - 1));
7590 }
7591 }
7592 }
7593 return *result;
7594}
7595
7596
7597RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007598 NoHandleAllocation ha;
7599 ASSERT(args.length() == 3);
7600
7601 JSFunction* callee = JSFunction::cast(args[0]);
7602 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007603 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007604
lrn@chromium.org303ada72010-10-27 09:33:13 +00007605 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007606 { MaybeObject* maybe_result =
7607 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007608 if (!maybe_result->ToObject(&result)) return maybe_result;
7609 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007610 // Allocate the elements if needed.
7611 if (length > 0) {
7612 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007613 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007614 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007615 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7616 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007617
7618 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007619 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007620 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007621 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007622
7623 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007624 for (int i = 0; i < length; i++) {
7625 array->set(i, *--parameters, mode);
7626 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007627 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007628 }
7629 return result;
7630}
7631
7632
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007633RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007634 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007635 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007636 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007637 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007638 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007639
whesse@chromium.org7b260152011-06-20 15:33:18 +00007640 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007641 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007642 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007643 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007644 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7645 context,
7646 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007647 return *result;
7648}
7649
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007650
7651static SmartPointer<Object**> GetNonBoundArguments(int bound_argc,
7652 int* total_argc) {
7653 // Find frame containing arguments passed to the caller.
7654 JavaScriptFrameIterator it;
7655 JavaScriptFrame* frame = it.frame();
7656 List<JSFunction*> functions(2);
7657 frame->GetFunctions(&functions);
7658 if (functions.length() > 1) {
7659 int inlined_frame_index = functions.length() - 1;
7660 JSFunction* inlined_function = functions[inlined_frame_index];
7661 int args_count = inlined_function->shared()->formal_parameter_count();
7662 ScopedVector<SlotRef> args_slots(args_count);
7663 SlotRef::ComputeSlotMappingForArguments(frame,
7664 inlined_frame_index,
7665 &args_slots);
7666
7667 *total_argc = bound_argc + args_count;
7668 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7669 for (int i = 0; i < args_count; i++) {
7670 Handle<Object> val = args_slots[i].GetValue();
7671 param_data[bound_argc + i] = val.location();
7672 }
7673 return param_data;
7674 } else {
7675 it.AdvanceToArgumentsFrame();
7676 frame = it.frame();
7677 int args_count = frame->ComputeParametersCount();
7678
7679 *total_argc = bound_argc + args_count;
7680 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7681 for (int i = 0; i < args_count; i++) {
7682 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7683 param_data[bound_argc + i] = val.location();
7684 }
7685 return param_data;
7686 }
7687}
7688
7689
7690RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007691 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007692 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007693 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007694 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007695
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007696 // Second argument is either null or an array of bound arguments.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007697 Handle<FixedArray> bound_args;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007698 int bound_argc = 0;
7699 if (!args[1]->IsNull()) {
7700 CONVERT_ARG_CHECKED(JSArray, params, 1);
7701 RUNTIME_ASSERT(params->HasFastElements());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007702 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007703 bound_argc = Smi::cast(params->length())->value();
7704 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007705
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007706 int total_argc = 0;
7707 SmartPointer<Object**> param_data =
7708 GetNonBoundArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007709 for (int i = 0; i < bound_argc; i++) {
7710 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007711 param_data[i] = val.location();
7712 }
7713
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007714 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007715 Handle<Object> result =
7716 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007717 if (exception) {
7718 return Failure::Exception();
7719 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007720
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007721 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007722 return *result;
7723}
7724
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007725
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007726static void TrySettingInlineConstructStub(Isolate* isolate,
7727 Handle<JSFunction> function) {
7728 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007729 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007730 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007731 }
7732 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007733 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00007734 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007735 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007736 function->shared()->set_construct_stub(
7737 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007738 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007739 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007740}
7741
7742
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007743RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007744 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007745 ASSERT(args.length() == 1);
7746
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007747 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007748
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007749 // If the constructor isn't a proper function we throw a type error.
7750 if (!constructor->IsJSFunction()) {
7751 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7752 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007753 isolate->factory()->NewTypeError("not_constructor", arguments);
7754 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007755 }
7756
7757 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007758
7759 // If function should not have prototype, construction is not allowed. In this
7760 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00007761 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007762 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7763 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007764 isolate->factory()->NewTypeError("not_constructor", arguments);
7765 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007766 }
7767
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007768#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007769 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007770 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007771 if (debug->StepInActive()) {
7772 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007773 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007774#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007775
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007776 if (function->has_initial_map()) {
7777 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007778 // The 'Function' function ignores the receiver object when
7779 // called using 'new' and creates a new JSFunction object that
7780 // is returned. The receiver object is only used for error
7781 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007782 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007783 // allocate JSFunctions since it does not properly initialize
7784 // the shared part of the function. Since the receiver is
7785 // ignored anyway, we use the global object as the receiver
7786 // instead of a new JSFunction object. This way, errors are
7787 // reported the same way whether or not 'Function' is called
7788 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007789 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007790 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007791 }
7792
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007793 // The function should be compiled for the optimization hints to be
7794 // available. We cannot use EnsureCompiled because that forces a
7795 // compilation through the shared function info which makes it
7796 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007797 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007798 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007799
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007800 if (!function->has_initial_map() &&
7801 shared->IsInobjectSlackTrackingInProgress()) {
7802 // The tracking is already in progress for another function. We can only
7803 // track one initial_map at a time, so we force the completion before the
7804 // function is called as a constructor for the first time.
7805 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007806 }
7807
7808 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007809 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7810 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007811 // Delay setting the stub if inobject slack tracking is in progress.
7812 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007813 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007814 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007815
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007816 isolate->counters()->constructed_objects()->Increment();
7817 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007818
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007819 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007820}
7821
7822
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007823RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007824 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007825 ASSERT(args.length() == 1);
7826
7827 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7828 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007829 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007830
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007831 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007832}
7833
7834
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007835RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007836 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007837 ASSERT(args.length() == 1);
7838
7839 Handle<JSFunction> function = args.at<JSFunction>(0);
7840#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007841 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007842 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007843 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007844 PrintF("]\n");
7845 }
7846#endif
7847
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007848 // Compile the target function. Here we compile using CompileLazyInLoop in
7849 // order to get the optimized version. This helps code like delta-blue
7850 // that calls performance-critical routines through constructors. A
7851 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
7852 // direct call. Since the in-loop tracking takes place through CallICs
7853 // this means that things called through constructors are never known to
7854 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007855 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007856 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007857 return Failure::Exception();
7858 }
7859
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007860 // All done. Return the compiled code.
7861 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007862 return function->code();
7863}
7864
7865
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007866RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007867 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007868 ASSERT(args.length() == 1);
7869 Handle<JSFunction> function = args.at<JSFunction>(0);
7870 // If the function is not optimizable or debugger is active continue using the
7871 // code from the full compiler.
7872 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007873 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007874 if (FLAG_trace_opt) {
7875 PrintF("[failed to optimize ");
7876 function->PrintName();
7877 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7878 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007879 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007880 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007881 function->ReplaceCode(function->shared()->code());
7882 return function->code();
7883 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007884 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007885 return function->code();
7886 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007887 if (FLAG_trace_opt) {
7888 PrintF("[failed to optimize ");
7889 function->PrintName();
7890 PrintF(": optimized compilation failed]\n");
7891 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007892 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007893 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007894}
7895
7896
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007897RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007898 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007899 ASSERT(args.length() == 1);
7900 RUNTIME_ASSERT(args[0]->IsSmi());
7901 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007902 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007903 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
7904 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007905 int frames = deoptimizer->output_count();
7906
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007907 deoptimizer->MaterializeHeapNumbers();
7908 delete deoptimizer;
7909
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007910 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007911 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007912 for (int i = 0; i < frames - 1; i++) it.Advance();
7913 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007914
7915 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007916 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007917 Handle<Object> arguments;
7918 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007919 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007920 if (arguments.is_null()) {
7921 // FunctionGetArguments can't throw an exception, so cast away the
7922 // doubt with an assert.
7923 arguments = Handle<Object>(
7924 Accessors::FunctionGetArguments(*function,
7925 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007926 ASSERT(*arguments != isolate->heap()->null_value());
7927 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007928 }
7929 frame->SetExpression(i, *arguments);
7930 }
7931 }
7932
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007933 if (type == Deoptimizer::EAGER) {
7934 RUNTIME_ASSERT(function->IsOptimized());
7935 } else {
7936 RUNTIME_ASSERT(!function->IsOptimized());
7937 }
7938
7939 // Avoid doing too much work when running with --always-opt and keep
7940 // the optimized code around.
7941 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007942 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007943 }
7944
7945 // Count the number of optimized activations of the function.
7946 int activations = 0;
7947 while (!it.done()) {
7948 JavaScriptFrame* frame = it.frame();
7949 if (frame->is_optimized() && frame->function() == *function) {
7950 activations++;
7951 }
7952 it.Advance();
7953 }
7954
7955 // TODO(kasperl): For now, we cannot support removing the optimized
7956 // code when we have recursive invocations of the same function.
7957 if (activations == 0) {
7958 if (FLAG_trace_deopt) {
7959 PrintF("[removing optimized code for: ");
7960 function->PrintName();
7961 PrintF("]\n");
7962 }
7963 function->ReplaceCode(function->shared()->code());
7964 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007965 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007966}
7967
7968
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007969RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007970 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007971 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007972 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007973}
7974
7975
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007976RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007977 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007978 ASSERT(args.length() == 1);
7979 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007980 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007981
7982 Deoptimizer::DeoptimizeFunction(*function);
7983
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007984 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007985}
7986
7987
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007988RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
7989#if defined(USE_SIMULATOR)
7990 return isolate->heap()->true_value();
7991#else
7992 return isolate->heap()->false_value();
7993#endif
7994}
7995
7996
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00007997RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
7998 HandleScope scope(isolate);
7999 ASSERT(args.length() == 1);
8000 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8001 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8002 function->MarkForLazyRecompilation();
8003 return isolate->heap()->undefined_value();
8004}
8005
8006
lrn@chromium.org1c092762011-05-09 09:42:16 +00008007RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8008 HandleScope scope(isolate);
8009 ASSERT(args.length() == 1);
8010 if (!V8::UseCrankshaft()) {
8011 return Smi::FromInt(4); // 4 == "never".
8012 }
8013 if (FLAG_always_opt) {
8014 return Smi::FromInt(3); // 3 == "always".
8015 }
8016 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8017 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8018 : Smi::FromInt(2); // 2 == "no".
8019}
8020
8021
8022RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8023 HandleScope scope(isolate);
8024 ASSERT(args.length() == 1);
8025 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8026 return Smi::FromInt(function->shared()->opt_count());
8027}
8028
8029
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008030RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008031 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008032 ASSERT(args.length() == 1);
8033 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8034
8035 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008036 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008037
8038 // We have hit a back edge in an unoptimized frame for a function that was
8039 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008040 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008041 // Keep track of whether we've succeeded in optimizing.
8042 bool succeeded = unoptimized->optimizable();
8043 if (succeeded) {
8044 // If we are trying to do OSR when there are already optimized
8045 // activations of the function, it means (a) the function is directly or
8046 // indirectly recursive and (b) an optimized invocation has been
8047 // deoptimized so that we are currently in an unoptimized activation.
8048 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008049 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008050 while (succeeded && !it.done()) {
8051 JavaScriptFrame* frame = it.frame();
8052 succeeded = !frame->is_optimized() || frame->function() != *function;
8053 it.Advance();
8054 }
8055 }
8056
8057 int ast_id = AstNode::kNoNumber;
8058 if (succeeded) {
8059 // The top JS function is this one, the PC is somewhere in the
8060 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008061 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008062 JavaScriptFrame* frame = it.frame();
8063 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008064 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008065 ASSERT(unoptimized->contains(frame->pc()));
8066
8067 // Use linear search of the unoptimized code's stack check table to find
8068 // the AST id matching the PC.
8069 Address start = unoptimized->instruction_start();
8070 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008071 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008072 uint32_t table_length = Memory::uint32_at(table_cursor);
8073 table_cursor += kIntSize;
8074 for (unsigned i = 0; i < table_length; ++i) {
8075 // Table entries are (AST id, pc offset) pairs.
8076 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8077 if (pc_offset == target_pc_offset) {
8078 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8079 break;
8080 }
8081 table_cursor += 2 * kIntSize;
8082 }
8083 ASSERT(ast_id != AstNode::kNoNumber);
8084 if (FLAG_trace_osr) {
8085 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8086 function->PrintName();
8087 PrintF("]\n");
8088 }
8089
8090 // Try to compile the optimized code. A true return value from
8091 // CompileOptimized means that compilation succeeded, not necessarily
8092 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008093 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
8094 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008095 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8096 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008097 if (data->OsrPcOffset()->value() >= 0) {
8098 if (FLAG_trace_osr) {
8099 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008100 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008101 }
8102 ASSERT(data->OsrAstId()->value() == ast_id);
8103 } else {
8104 // We may never generate the desired OSR entry if we emit an
8105 // early deoptimize.
8106 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008107 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008108 } else {
8109 succeeded = false;
8110 }
8111 }
8112
8113 // Revert to the original stack checks in the original unoptimized code.
8114 if (FLAG_trace_osr) {
8115 PrintF("[restoring original stack checks in ");
8116 function->PrintName();
8117 PrintF("]\n");
8118 }
8119 StackCheckStub check_stub;
8120 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008121 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008122 Deoptimizer::RevertStackCheckCode(*unoptimized,
8123 *check_code,
8124 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008125
8126 // Allow OSR only at nesting level zero again.
8127 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8128
8129 // If the optimization attempt succeeded, return the AST id tagged as a
8130 // smi. This tells the builtin that we need to translate the unoptimized
8131 // frame to an optimized one.
8132 if (succeeded) {
8133 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8134 return Smi::FromInt(ast_id);
8135 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008136 if (function->IsMarkedForLazyRecompilation()) {
8137 function->ReplaceCode(function->shared()->code());
8138 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008139 return Smi::FromInt(-1);
8140 }
8141}
8142
8143
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008144RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008145 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008146 ASSERT(args.length() == 1);
8147 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8148 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8149}
8150
8151
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008152RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008153 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008154 ASSERT(args.length() == 1);
8155 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8156 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8157}
8158
8159
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008160RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008161 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008162 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008163
kasper.lund7276f142008-07-30 08:49:36 +00008164 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00008165 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008166 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008167 { MaybeObject* maybe_result =
8168 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008169 if (!maybe_result->ToObject(&result)) return maybe_result;
8170 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008171
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008172 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008173
kasper.lund7276f142008-07-30 08:49:36 +00008174 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008175}
8176
lrn@chromium.org303ada72010-10-27 09:33:13 +00008177
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008178RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8179 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008180 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008181 JSObject* extension_object;
8182 if (args[0]->IsJSObject()) {
8183 extension_object = JSObject::cast(args[0]);
8184 } else {
8185 // Convert the object to a proper JavaScript object.
8186 MaybeObject* maybe_js_object = args[0]->ToObject();
8187 if (!maybe_js_object->To(&extension_object)) {
8188 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8189 HandleScope scope(isolate);
8190 Handle<Object> handle = args.at<Object>(0);
8191 Handle<Object> result =
8192 isolate->factory()->NewTypeError("with_expression",
8193 HandleVector(&handle, 1));
8194 return isolate->Throw(*result);
8195 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008196 return maybe_js_object;
8197 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008198 }
8199 }
8200
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008201 JSFunction* function;
8202 if (args[1]->IsSmi()) {
8203 // A smi sentinel indicates a context nested inside global code rather
8204 // than some function. There is a canonical empty function that can be
8205 // gotten from the global context.
8206 function = isolate->context()->global_context()->closure();
8207 } else {
8208 function = JSFunction::cast(args[1]);
8209 }
8210
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008211 Context* context;
8212 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008213 isolate->heap()->AllocateWithContext(function,
8214 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008215 extension_object);
8216 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008217 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008218 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008219}
8220
8221
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008222RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008223 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008224 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008225 String* name = String::cast(args[0]);
8226 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008227 JSFunction* function;
8228 if (args[2]->IsSmi()) {
8229 // A smi sentinel indicates a context nested inside global code rather
8230 // than some function. There is a canonical empty function that can be
8231 // gotten from the global context.
8232 function = isolate->context()->global_context()->closure();
8233 } else {
8234 function = JSFunction::cast(args[2]);
8235 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008236 Context* context;
8237 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008238 isolate->heap()->AllocateCatchContext(function,
8239 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008240 name,
8241 thrown_object);
8242 if (!maybe_context->To(&context)) return maybe_context;
8243 isolate->set_context(context);
8244 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008245}
8246
8247
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008248RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008249 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008250 ASSERT(args.length() == 2);
8251
8252 CONVERT_ARG_CHECKED(Context, context, 0);
8253 CONVERT_ARG_CHECKED(String, name, 1);
8254
8255 int index;
8256 PropertyAttributes attributes;
8257 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008258 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008259
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008260 // If the slot was not found the result is true.
8261 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008262 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008263 }
8264
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008265 // If the slot was found in a context, it should be DONT_DELETE.
8266 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008267 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008268 }
8269
8270 // The slot was found in a JSObject, either a context extension object,
8271 // the global object, or an arguments object. Try to delete it
8272 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
8273 // which allows deleting all parameters in functions that mention
8274 // 'arguments', we do this even for the case of slots found on an
8275 // arguments object. The slot was found on an arguments object if the
8276 // index is non-negative.
8277 Handle<JSObject> object = Handle<JSObject>::cast(holder);
8278 if (index >= 0) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008279 return object->DeleteElement(index, JSReceiver::NORMAL_DELETION);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008280 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008281 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008282 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008283}
8284
8285
ager@chromium.orga1645e22009-09-09 19:27:10 +00008286// A mechanism to return a pair of Object pointers in registers (if possible).
8287// How this is achieved is calling convention-dependent.
8288// All currently supported x86 compiles uses calling conventions that are cdecl
8289// variants where a 64-bit value is returned in two 32-bit registers
8290// (edx:eax on ia32, r1:r0 on ARM).
8291// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8292// In Win64 calling convention, a struct of two pointers is returned in memory,
8293// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008294#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008295struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008296 MaybeObject* x;
8297 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008298};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008299
lrn@chromium.org303ada72010-10-27 09:33:13 +00008300static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008301 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008302 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8303 // In Win64 they are assigned to a hidden first argument.
8304 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008305}
8306#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008307typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008308static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008309 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008310 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008311}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008312#endif
8313
8314
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008315static inline MaybeObject* Unhole(Heap* heap,
8316 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008317 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008318 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8319 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008320 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008321}
8322
8323
danno@chromium.org40cb8782011-05-25 07:58:50 +00008324static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8325 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008326 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008327 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008328 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008329 JSFunction* context_extension_function =
8330 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008331 // If the holder isn't a context extension object, we just return it
8332 // as the receiver. This allows arguments objects to be used as
8333 // receivers, but only if they are put in the context scope chain
8334 // explicitly via a with-statement.
8335 Object* constructor = holder->map()->constructor();
8336 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008337 // Fall back to using the global object as the implicit receiver if
8338 // the property turns out to be a local variable allocated in a
8339 // context extension object - introduced via eval. Implicit global
8340 // receivers are indicated with the hole value.
8341 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008342}
8343
8344
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008345static ObjectPair LoadContextSlotHelper(Arguments args,
8346 Isolate* isolate,
8347 bool throw_error) {
8348 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008349 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008350
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008351 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008352 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008353 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008354 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008355 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008356
8357 int index;
8358 PropertyAttributes attributes;
8359 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008360 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008361
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008362 // If the index is non-negative, the slot has been found in a local
8363 // variable or a parameter. Read it from the context object or the
8364 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008365 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008366 // If the "property" we were looking for is a local variable or an
8367 // argument in a context, the receiver is the global object; see
8368 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008369 //
8370 // Use the hole as the receiver to signal that the receiver is
8371 // implicit and that the global receiver should be used.
8372 Handle<Object> receiver = isolate->factory()->the_hole_value();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008373 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008374 ? Context::cast(*holder)->get(index)
8375 : JSObject::cast(*holder)->GetElement(index);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008376 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008377 }
8378
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008379 // If the holder is found, we read the property from it.
8380 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008381 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008382 JSObject* object = JSObject::cast(*holder);
danno@chromium.org40cb8782011-05-25 07:58:50 +00008383 Object* receiver;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008384 if (object->IsGlobalObject()) {
8385 receiver = GlobalObject::cast(object)->global_receiver();
8386 } else if (context->is_exception_holder(*holder)) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008387 // Use the hole as the receiver to signal that the receiver is
8388 // implicit and that the global receiver should be used.
8389 receiver = isolate->heap()->the_hole_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008390 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008391 receiver = ComputeReceiverForNonGlobal(isolate, object);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008392 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008393
8394 // GetProperty below can cause GC.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008395 Handle<Object> receiver_handle(receiver);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008396
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008397 // No need to unhole the value here. This is taken care of by the
8398 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008399 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008400 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008401 }
8402
8403 if (throw_error) {
8404 // The property doesn't exist - throw exception.
8405 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008406 isolate->factory()->NewReferenceError("not_defined",
8407 HandleVector(&name, 1));
8408 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008409 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008410 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008411 return MakePair(isolate->heap()->undefined_value(),
8412 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008413 }
8414}
8415
8416
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008417RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008418 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008419}
8420
8421
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008422RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008423 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008424}
8425
8426
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008427RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008428 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008429 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008430
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008431 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008432 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008433 CONVERT_ARG_CHECKED(String, name, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008434 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008435 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
8436 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008437 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008438
8439 int index;
8440 PropertyAttributes attributes;
8441 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008442 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008443
8444 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008445 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008446 // Ignore if read_only variable.
8447 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008448 // Context is a fixed array and set cannot fail.
8449 Context::cast(*holder)->set(index, *value);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008450 } else if (strict_mode == kStrictMode) {
8451 // Setting read only property in strict mode.
8452 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008453 isolate->factory()->NewTypeError("strict_cannot_assign",
8454 HandleVector(&name, 1));
8455 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008456 }
8457 } else {
8458 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008459 Handle<Object> result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008460 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008461 if (result.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008462 ASSERT(isolate->has_pending_exception());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008463 return Failure::Exception();
8464 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008465 }
8466 return *value;
8467 }
8468
8469 // Slow case: The property is not in a FixedArray context.
8470 // It is either in an JSObject extension context or it was not found.
8471 Handle<JSObject> context_ext;
8472
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008473 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008474 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008475 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008476 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008477 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008478 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008479
8480 if (strict_mode == kStrictMode) {
8481 // Throw in strict mode (assignment to undefined variable).
8482 Handle<Object> error =
8483 isolate->factory()->NewReferenceError(
8484 "not_defined", HandleVector(&name, 1));
8485 return isolate->Throw(*error);
8486 }
8487 // In non-strict mode, the property is stored in the global context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008488 attributes = NONE;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008489 context_ext = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008490 }
8491
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008492 // Set the property, but ignore if read_only variable on the context
8493 // extension object itself.
8494 if ((attributes & READ_ONLY) == 0 ||
8495 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008496 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008497 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008498 SetProperty(context_ext, name, value, NONE, strict_mode));
8499 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008500 // Setting read only property in strict mode.
8501 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008502 isolate->factory()->NewTypeError(
8503 "strict_cannot_assign", HandleVector(&name, 1));
8504 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008505 }
8506 return *value;
8507}
8508
8509
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008510RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008511 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008512 ASSERT(args.length() == 1);
8513
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008514 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008515}
8516
8517
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008518RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008519 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008520 ASSERT(args.length() == 1);
8521
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008522 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008523}
8524
8525
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008526RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008527 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008528 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008529}
8530
8531
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008532RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008533 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008534 ASSERT(args.length() == 1);
8535
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008536 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008537 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008538 isolate->factory()->NewReferenceError("not_defined",
8539 HandleVector(&name, 1));
8540 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008541}
8542
8543
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008544RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008545 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008546
8547 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008548 if (isolate->stack_guard()->IsStackOverflow()) {
8549 NoHandleAllocation na;
8550 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008551 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008552
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008553 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008554}
8555
8556
8557// NOTE: These PrintXXX functions are defined for all builds (not just
8558// DEBUG builds) because we may want to be able to trace function
8559// calls in all modes.
8560static void PrintString(String* str) {
8561 // not uncommon to have empty strings
8562 if (str->length() > 0) {
8563 SmartPointer<char> s =
8564 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
8565 PrintF("%s", *s);
8566 }
8567}
8568
8569
8570static void PrintObject(Object* obj) {
8571 if (obj->IsSmi()) {
8572 PrintF("%d", Smi::cast(obj)->value());
8573 } else if (obj->IsString() || obj->IsSymbol()) {
8574 PrintString(String::cast(obj));
8575 } else if (obj->IsNumber()) {
8576 PrintF("%g", obj->Number());
8577 } else if (obj->IsFailure()) {
8578 PrintF("<failure>");
8579 } else if (obj->IsUndefined()) {
8580 PrintF("<undefined>");
8581 } else if (obj->IsNull()) {
8582 PrintF("<null>");
8583 } else if (obj->IsTrue()) {
8584 PrintF("<true>");
8585 } else if (obj->IsFalse()) {
8586 PrintF("<false>");
8587 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008588 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008589 }
8590}
8591
8592
8593static int StackSize() {
8594 int n = 0;
8595 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8596 return n;
8597}
8598
8599
8600static void PrintTransition(Object* result) {
8601 // indentation
8602 { const int nmax = 80;
8603 int n = StackSize();
8604 if (n <= nmax)
8605 PrintF("%4d:%*s", n, n, "");
8606 else
8607 PrintF("%4d:%*s", n, nmax, "...");
8608 }
8609
8610 if (result == NULL) {
8611 // constructor calls
8612 JavaScriptFrameIterator it;
8613 JavaScriptFrame* frame = it.frame();
8614 if (frame->IsConstructor()) PrintF("new ");
8615 // function name
8616 Object* fun = frame->function();
8617 if (fun->IsJSFunction()) {
8618 PrintObject(JSFunction::cast(fun)->shared()->name());
8619 } else {
8620 PrintObject(fun);
8621 }
8622 // function arguments
8623 // (we are intentionally only printing the actually
8624 // supplied parameters, not all parameters required)
8625 PrintF("(this=");
8626 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008627 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008628 for (int i = 0; i < length; i++) {
8629 PrintF(", ");
8630 PrintObject(frame->GetParameter(i));
8631 }
8632 PrintF(") {\n");
8633
8634 } else {
8635 // function result
8636 PrintF("} -> ");
8637 PrintObject(result);
8638 PrintF("\n");
8639 }
8640}
8641
8642
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008643RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008644 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008645 NoHandleAllocation ha;
8646 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008647 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008648}
8649
8650
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008651RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008652 NoHandleAllocation ha;
8653 PrintTransition(args[0]);
8654 return args[0]; // return TOS
8655}
8656
8657
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008658RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008659 NoHandleAllocation ha;
8660 ASSERT(args.length() == 1);
8661
8662#ifdef DEBUG
8663 if (args[0]->IsString()) {
8664 // If we have a string, assume it's a code "marker"
8665 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008666 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008667 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008668 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8669 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008670 } else {
8671 PrintF("DebugPrint: ");
8672 }
8673 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008674 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008675 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008676 HeapObject::cast(args[0])->map()->Print();
8677 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008678#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008679 // ShortPrint is available in release mode. Print is not.
8680 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008681#endif
8682 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00008683 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008684
8685 return args[0]; // return TOS
8686}
8687
8688
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008689RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008690 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008691 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008692 isolate->PrintStack();
8693 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008694}
8695
8696
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008697RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008698 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008699 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008700
8701 // According to ECMA-262, section 15.9.1, page 117, the precision of
8702 // the number in a Date object representing a particular instant in
8703 // time is milliseconds. Therefore, we floor the result of getting
8704 // the OS time.
8705 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008706 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008707}
8708
8709
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008710RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008711 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008712 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008713
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008714 CONVERT_ARG_CHECKED(String, str, 0);
8715 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008716
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008717 CONVERT_ARG_CHECKED(JSArray, output, 1);
8718 RUNTIME_ASSERT(output->HasFastElements());
8719
8720 AssertNoAllocation no_allocation;
8721
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008722 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008723 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
8724 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008725 if (str->IsAsciiRepresentation()) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008726 result = DateParser::Parse(str->ToAsciiVector(),
8727 output_array,
8728 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008729 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008730 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008731 result = DateParser::Parse(str->ToUC16Vector(),
8732 output_array,
8733 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008734 }
8735
8736 if (result) {
8737 return *output;
8738 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008739 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008740 }
8741}
8742
8743
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008744RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008745 NoHandleAllocation ha;
8746 ASSERT(args.length() == 1);
8747
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008748 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00008749 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008750 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008751}
8752
8753
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008754RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008755 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008756 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008757
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008758 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008759}
8760
8761
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008762RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008763 NoHandleAllocation ha;
8764 ASSERT(args.length() == 1);
8765
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008766 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008767 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008768}
8769
8770
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008771RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008772 ASSERT(args.length() == 1);
8773 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008774 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008775 return JSGlobalObject::cast(global)->global_receiver();
8776}
8777
8778
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008779RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008780 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008781 ASSERT_EQ(1, args.length());
8782 CONVERT_ARG_CHECKED(String, source, 0);
8783
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00008784 source = Handle<String>(source->TryFlattenGetString());
8785 // Optimized fast case where we only have ascii characters.
8786 Handle<Object> result;
8787 if (source->IsSeqAsciiString()) {
8788 result = JsonParser<true>::Parse(source);
8789 } else {
8790 result = JsonParser<false>::Parse(source);
8791 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008792 if (result.is_null()) {
8793 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008794 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008795 return Failure::Exception();
8796 }
8797 return *result;
8798}
8799
8800
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008801bool CodeGenerationFromStringsAllowed(Isolate* isolate,
8802 Handle<Context> context) {
8803 if (context->allow_code_gen_from_strings()->IsFalse()) {
8804 // Check with callback if set.
8805 AllowCodeGenerationFromStringsCallback callback =
8806 isolate->allow_code_gen_callback();
8807 if (callback == NULL) {
8808 // No callback set and code generation disallowed.
8809 return false;
8810 } else {
8811 // Callback set. Let it decide if code generation is allowed.
8812 VMState state(isolate, EXTERNAL);
8813 return callback(v8::Utils::ToLocal(context));
8814 }
8815 }
8816 return true;
8817}
8818
8819
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008820RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008821 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008822 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008823 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008824
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008825 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008826 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008827
8828 // Check if global context allows code generation from
8829 // strings. Throw an exception if it doesn't.
8830 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
8831 return isolate->Throw(*isolate->factory()->NewError(
8832 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8833 }
8834
8835 // Compile source string in the global context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008836 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
8837 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008838 true,
8839 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008840 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008841 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008842 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8843 context,
8844 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008845 return *fun;
8846}
8847
8848
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008849static ObjectPair CompileGlobalEval(Isolate* isolate,
8850 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008851 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008852 StrictModeFlag strict_mode) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008853 Handle<Context> context = Handle<Context>(isolate->context());
8854 Handle<Context> global_context = Handle<Context>(context->global_context());
8855
8856 // Check if global context allows code generation from
8857 // strings. Throw an exception if it doesn't.
8858 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
8859 isolate->Throw(*isolate->factory()->NewError(
8860 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8861 return MakePair(Failure::Exception(), NULL);
8862 }
8863
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008864 // Deal with a normal eval call with a string argument. Compile it
8865 // and return the compiled function bound in the local context.
8866 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
8867 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008868 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008869 context->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008870 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008871 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008872 Handle<JSFunction> compiled =
8873 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008874 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008875 return MakePair(*compiled, *receiver);
8876}
8877
8878
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008879RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008880 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008881
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008882 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008883 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008884 Handle<Object> receiver; // Will be overwritten.
8885
8886 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008887 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008888#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008889 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008890 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008891 StackFrameLocator locator;
8892 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008893 ASSERT(Context::cast(frame->context()) == *context);
8894#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008895
8896 // Find where the 'eval' symbol is bound. It is unaliased only if
8897 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008898 int index = -1;
8899 PropertyAttributes attributes = ABSENT;
8900 while (true) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008901 receiver = context->Lookup(isolate->factory()->eval_symbol(),
8902 FOLLOW_PROTOTYPE_CHAIN,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008903 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008904 // Stop search when eval is found or when the global context is
8905 // reached.
8906 if (attributes != ABSENT || context->IsGlobalContext()) break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008907 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008908 }
8909
iposva@chromium.org245aa852009-02-10 00:49:54 +00008910 // If eval could not be resolved, it has been deleted and we need to
8911 // throw a reference error.
8912 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008913 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00008914 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008915 isolate->factory()->NewReferenceError("not_defined",
8916 HandleVector(&name, 1));
8917 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008918 }
8919
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008920 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008921 // 'eval' is not bound in the global context. Just call the function
8922 // with the given arguments. This is not necessarily the global eval.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00008923 if (receiver->IsContext() || receiver->IsJSContextExtensionObject()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008924 receiver = isolate->factory()->the_hole_value();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008925 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008926 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008927 }
8928
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008929 // 'eval' is bound in the global context, but it may have been overwritten.
8930 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008931 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008932 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008933 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008934 }
8935
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008936 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008937 return CompileGlobalEval(isolate,
8938 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008939 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008940 static_cast<StrictModeFlag>(args.smi_at(3)));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008941}
8942
8943
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008944RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008945 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008946
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008947 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008948 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008949
8950 // 'eval' is bound in the global context, but it may have been overwritten.
8951 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008952 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008953 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008954 return MakePair(*callee, isolate->heap()->the_hole_value());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008955 }
8956
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008957 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008958 return CompileGlobalEval(isolate,
8959 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008960 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008961 static_cast<StrictModeFlag>(args.smi_at(3)));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008962}
8963
8964
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008965RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008966 // This utility adjusts the property attributes for newly created Function
8967 // object ("new Function(...)") by changing the map.
8968 // All it does is changing the prototype property to enumerable
8969 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008970 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008971 ASSERT(args.length() == 1);
8972 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008973
8974 Handle<Map> map = func->shared()->strict_mode()
8975 ? isolate->strict_mode_function_instance_map()
8976 : isolate->function_instance_map();
8977
8978 ASSERT(func->map()->instance_type() == map->instance_type());
8979 ASSERT(func->map()->instance_size() == map->instance_size());
8980 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008981 return *func;
8982}
8983
8984
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008985RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008986 // Allocate a block of memory in NewSpace (filled with a filler).
8987 // Use as fallback for allocation in generated code when NewSpace
8988 // is full.
8989 ASSERT(args.length() == 1);
8990 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
8991 int size = size_smi->value();
8992 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
8993 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008994 Heap* heap = isolate->heap();
8995 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008996 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008997 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008998 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008999 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009000 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009001 }
9002 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009003 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009004}
9005
9006
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009007// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009008// array. Returns true if the element was pushed on the stack and
9009// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009010RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009011 ASSERT(args.length() == 2);
9012 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009013 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009014 RUNTIME_ASSERT(array->HasFastElements());
9015 int length = Smi::cast(array->length())->value();
9016 FixedArray* elements = FixedArray::cast(array->elements());
9017 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009018 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009019 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009020 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009021 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009022 { MaybeObject* maybe_obj =
9023 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009024 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9025 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009026 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009027}
9028
9029
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009030/**
9031 * A simple visitor visits every element of Array's.
9032 * The backend storage can be a fixed array for fast elements case,
9033 * or a dictionary for sparse array. Since Dictionary is a subtype
9034 * of FixedArray, the class can be used by both fast and slow cases.
9035 * The second parameter of the constructor, fast_elements, specifies
9036 * whether the storage is a FixedArray or Dictionary.
9037 *
9038 * An index limit is used to deal with the situation that a result array
9039 * length overflows 32-bit non-negative integer.
9040 */
9041class ArrayConcatVisitor {
9042 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009043 ArrayConcatVisitor(Isolate* isolate,
9044 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009045 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009046 isolate_(isolate),
9047 storage_(Handle<FixedArray>::cast(
9048 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009049 index_offset_(0u),
9050 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009051
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009052 ~ArrayConcatVisitor() {
9053 clear_storage();
9054 }
9055
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009056 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009057 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009058 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009059
9060 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009061 if (index < static_cast<uint32_t>(storage_->length())) {
9062 storage_->set(index, *elm);
9063 return;
9064 }
9065 // Our initial estimate of length was foiled, possibly by
9066 // getters on the arrays increasing the length of later arrays
9067 // during iteration.
9068 // This shouldn't happen in anything but pathological cases.
9069 SetDictionaryMode(index);
9070 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009071 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009072 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009073 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009074 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009075 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009076 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009077 // Dictionary needed to grow.
9078 clear_storage();
9079 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009080 }
9081}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009082
9083 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009084 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9085 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009086 } else {
9087 index_offset_ += delta;
9088 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009089 }
9090
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009091 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009092 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009093 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009094 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009095 Handle<Map> map;
9096 if (fast_elements_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009097 map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009098 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009099 map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009100 }
9101 array->set_map(*map);
9102 array->set_length(*length);
9103 array->set_elements(*storage_);
9104 return array;
9105 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009106
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009107 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009108 // Convert storage to dictionary mode.
9109 void SetDictionaryMode(uint32_t index) {
9110 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009111 Handle<FixedArray> current_storage(*storage_);
9112 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009113 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009114 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9115 for (uint32_t i = 0; i < current_length; i++) {
9116 HandleScope loop_scope;
9117 Handle<Object> element(current_storage->get(i));
9118 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009119 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009120 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009121 if (!new_storage.is_identical_to(slow_storage)) {
9122 slow_storage = loop_scope.CloseAndEscape(new_storage);
9123 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009124 }
9125 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009126 clear_storage();
9127 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009128 fast_elements_ = false;
9129 }
9130
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009131 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009132 isolate_->global_handles()->Destroy(
9133 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009134 }
9135
9136 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009137 storage_ = Handle<FixedArray>::cast(
9138 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009139 }
9140
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009141 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009142 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009143 // Index after last seen index. Always less than or equal to
9144 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009145 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009146 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009147};
9148
9149
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009150static uint32_t EstimateElementCount(Handle<JSArray> array) {
9151 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9152 int element_count = 0;
9153 switch (array->GetElementsKind()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009154 case JSObject::FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009155 // Fast elements can't have lengths that are not representable by
9156 // a 32-bit signed integer.
9157 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9158 int fast_length = static_cast<int>(length);
9159 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9160 for (int i = 0; i < fast_length; i++) {
9161 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009162 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009163 break;
9164 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009165 case JSObject::DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009166 Handle<NumberDictionary> dictionary(
9167 NumberDictionary::cast(array->elements()));
9168 int capacity = dictionary->Capacity();
9169 for (int i = 0; i < capacity; i++) {
9170 Handle<Object> key(dictionary->KeyAt(i));
9171 if (dictionary->IsKey(*key)) {
9172 element_count++;
9173 }
9174 }
9175 break;
9176 }
9177 default:
9178 // External arrays are always dense.
9179 return length;
9180 }
9181 // As an estimate, we assume that the prototype doesn't contain any
9182 // inherited elements.
9183 return element_count;
9184}
9185
9186
9187
9188template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009189static void IterateExternalArrayElements(Isolate* isolate,
9190 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009191 bool elements_are_ints,
9192 bool elements_are_guaranteed_smis,
9193 ArrayConcatVisitor* visitor) {
9194 Handle<ExternalArrayClass> array(
9195 ExternalArrayClass::cast(receiver->elements()));
9196 uint32_t len = static_cast<uint32_t>(array->length());
9197
9198 ASSERT(visitor != NULL);
9199 if (elements_are_ints) {
9200 if (elements_are_guaranteed_smis) {
9201 for (uint32_t j = 0; j < len; j++) {
9202 HandleScope loop_scope;
9203 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
9204 visitor->visit(j, e);
9205 }
9206 } else {
9207 for (uint32_t j = 0; j < len; j++) {
9208 HandleScope loop_scope;
9209 int64_t val = static_cast<int64_t>(array->get(j));
9210 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9211 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9212 visitor->visit(j, e);
9213 } else {
9214 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009215 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009216 visitor->visit(j, e);
9217 }
9218 }
9219 }
9220 } else {
9221 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009222 HandleScope loop_scope(isolate);
9223 Handle<Object> e = isolate->factory()->NewNumber(array->get(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009224 visitor->visit(j, e);
9225 }
9226 }
9227}
9228
9229
9230// Used for sorting indices in a List<uint32_t>.
9231static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9232 uint32_t a = *ap;
9233 uint32_t b = *bp;
9234 return (a == b) ? 0 : (a < b) ? -1 : 1;
9235}
9236
9237
9238static void CollectElementIndices(Handle<JSObject> object,
9239 uint32_t range,
9240 List<uint32_t>* indices) {
9241 JSObject::ElementsKind kind = object->GetElementsKind();
9242 switch (kind) {
9243 case JSObject::FAST_ELEMENTS: {
9244 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9245 uint32_t length = static_cast<uint32_t>(elements->length());
9246 if (range < length) length = range;
9247 for (uint32_t i = 0; i < length; i++) {
9248 if (!elements->get(i)->IsTheHole()) {
9249 indices->Add(i);
9250 }
9251 }
9252 break;
9253 }
9254 case JSObject::DICTIONARY_ELEMENTS: {
9255 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009256 uint32_t capacity = dict->Capacity();
9257 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009258 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009259 Handle<Object> k(dict->KeyAt(j));
9260 if (dict->IsKey(*k)) {
9261 ASSERT(k->IsNumber());
9262 uint32_t index = static_cast<uint32_t>(k->Number());
9263 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009264 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009265 }
9266 }
9267 }
9268 break;
9269 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009270 default: {
9271 int dense_elements_length;
9272 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009273 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009274 dense_elements_length =
9275 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009276 break;
9277 }
9278 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009279 dense_elements_length =
9280 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009281 break;
9282 }
9283 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009284 dense_elements_length =
9285 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009286 break;
9287 }
9288 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009289 dense_elements_length =
9290 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009291 break;
9292 }
9293 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009294 dense_elements_length =
9295 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009296 break;
9297 }
9298 case JSObject::EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009299 dense_elements_length =
9300 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009301 break;
9302 }
9303 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009304 dense_elements_length =
9305 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009306 break;
9307 }
9308 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009309 dense_elements_length =
9310 ExternalFloatArray::cast(object->elements())->length();
9311 break;
9312 }
9313 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9314 dense_elements_length =
9315 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009316 break;
9317 }
9318 default:
9319 UNREACHABLE();
9320 dense_elements_length = 0;
9321 break;
9322 }
9323 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9324 if (range <= length) {
9325 length = range;
9326 // We will add all indices, so we might as well clear it first
9327 // and avoid duplicates.
9328 indices->Clear();
9329 }
9330 for (uint32_t i = 0; i < length; i++) {
9331 indices->Add(i);
9332 }
9333 if (length == range) return; // All indices accounted for already.
9334 break;
9335 }
9336 }
9337
9338 Handle<Object> prototype(object->GetPrototype());
9339 if (prototype->IsJSObject()) {
9340 // The prototype will usually have no inherited element indices,
9341 // but we have to check.
9342 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9343 }
9344}
9345
9346
9347/**
9348 * A helper function that visits elements of a JSArray in numerical
9349 * order.
9350 *
9351 * The visitor argument called for each existing element in the array
9352 * with the element index and the element's value.
9353 * Afterwards it increments the base-index of the visitor by the array
9354 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009355 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009356 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009357static bool IterateElements(Isolate* isolate,
9358 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009359 ArrayConcatVisitor* visitor) {
9360 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9361 switch (receiver->GetElementsKind()) {
9362 case JSObject::FAST_ELEMENTS: {
9363 // Run through the elements FixedArray and use HasElement and GetElement
9364 // to check the prototype for missing elements.
9365 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9366 int fast_length = static_cast<int>(length);
9367 ASSERT(fast_length <= elements->length());
9368 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009369 HandleScope loop_scope(isolate);
9370 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009371 if (!element_value->IsTheHole()) {
9372 visitor->visit(j, element_value);
9373 } else if (receiver->HasElement(j)) {
9374 // Call GetElement on receiver, not its prototype, or getters won't
9375 // have the correct receiver.
9376 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009377 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009378 visitor->visit(j, element_value);
9379 }
9380 }
9381 break;
9382 }
9383 case JSObject::DICTIONARY_ELEMENTS: {
9384 Handle<NumberDictionary> dict(receiver->element_dictionary());
9385 List<uint32_t> indices(dict->Capacity() / 2);
9386 // Collect all indices in the object and the prototypes less
9387 // than length. This might introduce duplicates in the indices list.
9388 CollectElementIndices(receiver, length, &indices);
9389 indices.Sort(&compareUInt32);
9390 int j = 0;
9391 int n = indices.length();
9392 while (j < n) {
9393 HandleScope loop_scope;
9394 uint32_t index = indices[j];
9395 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009396 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009397 visitor->visit(index, element);
9398 // Skip to next different index (i.e., omit duplicates).
9399 do {
9400 j++;
9401 } while (j < n && indices[j] == index);
9402 }
9403 break;
9404 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009405 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
9406 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9407 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009408 for (uint32_t j = 0; j < length; j++) {
9409 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
9410 visitor->visit(j, e);
9411 }
9412 break;
9413 }
9414 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
9415 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009416 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009417 break;
9418 }
9419 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
9420 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009421 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009422 break;
9423 }
9424 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
9425 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009426 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009427 break;
9428 }
9429 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
9430 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009431 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009432 break;
9433 }
9434 case JSObject::EXTERNAL_INT_ELEMENTS: {
9435 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009436 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009437 break;
9438 }
9439 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
9440 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009441 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009442 break;
9443 }
9444 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
9445 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009446 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009447 break;
9448 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009449 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9450 IterateExternalArrayElements<ExternalDoubleArray, double>(
9451 isolate, receiver, false, false, visitor);
9452 break;
9453 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009454 default:
9455 UNREACHABLE();
9456 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009457 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009458 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009459 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009460}
9461
9462
9463/**
9464 * Array::concat implementation.
9465 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009466 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009467 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009468 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009469RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009470 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009471 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009472
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009473 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
9474 int argument_count = static_cast<int>(arguments->length()->Number());
9475 RUNTIME_ASSERT(arguments->HasFastElements());
9476 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009477
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009478 // Pass 1: estimate the length and number of elements of the result.
9479 // The actual length can be larger if any of the arguments have getters
9480 // that mutate other arguments (but will otherwise be precise).
9481 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009482
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009483 uint32_t estimate_result_length = 0;
9484 uint32_t estimate_nof_elements = 0;
9485 {
9486 for (int i = 0; i < argument_count; i++) {
9487 HandleScope loop_scope;
9488 Handle<Object> obj(elements->get(i));
9489 uint32_t length_estimate;
9490 uint32_t element_estimate;
9491 if (obj->IsJSArray()) {
9492 Handle<JSArray> array(Handle<JSArray>::cast(obj));
9493 length_estimate =
9494 static_cast<uint32_t>(array->length()->Number());
9495 element_estimate =
9496 EstimateElementCount(array);
9497 } else {
9498 length_estimate = 1;
9499 element_estimate = 1;
9500 }
9501 // Avoid overflows by capping at kMaxElementCount.
9502 if (JSObject::kMaxElementCount - estimate_result_length <
9503 length_estimate) {
9504 estimate_result_length = JSObject::kMaxElementCount;
9505 } else {
9506 estimate_result_length += length_estimate;
9507 }
9508 if (JSObject::kMaxElementCount - estimate_nof_elements <
9509 element_estimate) {
9510 estimate_nof_elements = JSObject::kMaxElementCount;
9511 } else {
9512 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009513 }
9514 }
9515 }
9516
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009517 // If estimated number of elements is more than half of length, a
9518 // fixed array (fast case) is more time and space-efficient than a
9519 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009520 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009521
9522 Handle<FixedArray> storage;
9523 if (fast_case) {
9524 // The backing storage array must have non-existing elements to
9525 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009526 storage = isolate->factory()->NewFixedArrayWithHoles(
9527 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009528 } else {
9529 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9530 uint32_t at_least_space_for = estimate_nof_elements +
9531 (estimate_nof_elements >> 2);
9532 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009533 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009534 }
9535
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009536 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009537
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009538 for (int i = 0; i < argument_count; i++) {
9539 Handle<Object> obj(elements->get(i));
9540 if (obj->IsJSArray()) {
9541 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009542 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009543 return Failure::Exception();
9544 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009545 } else {
9546 visitor.visit(0, obj);
9547 visitor.increase_index_offset(1);
9548 }
9549 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009550
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009551 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009552}
9553
9554
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009555// This will not allocate (flatten the string), but it may run
9556// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009557RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009558 NoHandleAllocation ha;
9559 ASSERT(args.length() == 1);
9560
9561 CONVERT_CHECKED(String, string, args[0]);
9562 StringInputBuffer buffer(string);
9563 while (buffer.has_more()) {
9564 uint16_t character = buffer.GetNext();
9565 PrintF("%c", character);
9566 }
9567 return string;
9568}
9569
ager@chromium.org5ec48922009-05-05 07:25:34 +00009570// Moves all own elements of an object, that are below a limit, to positions
9571// starting at zero. All undefined values are placed after non-undefined values,
9572// and are followed by non-existing element. Does not change the length
9573// property.
9574// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009575RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009576 ASSERT(args.length() == 2);
9577 CONVERT_CHECKED(JSObject, object, args[0]);
9578 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9579 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009580}
9581
9582
9583// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009584RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009585 ASSERT(args.length() == 2);
9586 CONVERT_CHECKED(JSArray, from, args[0]);
9587 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009588 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009589 MaybeObject* maybe_new_map;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009590 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9591 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009592 maybe_new_map = to->map()->GetFastElementsMap();
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009593 } else if (new_elements->map() ==
9594 isolate->heap()->fixed_double_array_map()) {
9595 maybe_new_map = to->map()->GetFastDoubleElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009596 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009597 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009598 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009599 Object* new_map;
9600 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009601 to->set_map(Map::cast(new_map));
9602 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009603 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009604 Object* obj;
9605 { MaybeObject* maybe_obj = from->ResetElements();
9606 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9607 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009608 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009609 return to;
9610}
9611
9612
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009613// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009614RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009615 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009616 CONVERT_CHECKED(JSObject, object, args[0]);
9617 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009618 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009619 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009620 } else if (object->IsJSArray()) {
9621 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009622 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009623 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009624 }
9625}
9626
9627
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009628RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009629 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009630
9631 ASSERT_EQ(3, args.length());
9632
ager@chromium.orgac091b72010-05-05 07:34:42 +00009633 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009634 Handle<Object> key1 = args.at<Object>(1);
9635 Handle<Object> key2 = args.at<Object>(2);
9636
9637 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009638 if (!key1->ToArrayIndex(&index1)
9639 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009640 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009641 }
9642
ager@chromium.orgac091b72010-05-05 07:34:42 +00009643 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
9644 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009645 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009646 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009647 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009648
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009649 RETURN_IF_EMPTY_HANDLE(isolate,
9650 SetElement(jsobject, index1, tmp2, kStrictMode));
9651 RETURN_IF_EMPTY_HANDLE(isolate,
9652 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00009653
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009654 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009655}
9656
9657
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009658// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009659// might have elements. Can either return keys (positive integers) or
9660// intervals (pair of a negative integer (-start-1) followed by a
9661// positive (length)) or undefined values.
9662// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009663RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009664 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009665 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009666 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009667 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009668 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009669 // Create an array and get all the keys into it, then remove all the
9670 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009671 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009672 int keys_length = keys->length();
9673 for (int i = 0; i < keys_length; i++) {
9674 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009675 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009676 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009677 // Zap invalid keys.
9678 keys->set_undefined(i);
9679 }
9680 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009681 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009682 } else {
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009683 ASSERT(array->HasFastElements() || array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009684 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009685 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009686 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009687 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009688 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009689 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009690 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009691 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009692 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009693 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009694 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009695 }
9696}
9697
9698
9699// DefineAccessor takes an optional final argument which is the
9700// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
9701// to the way accessors are implemented, it is set for both the getter
9702// and setter on the first call to DefineAccessor and ignored on
9703// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009704RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009705 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
9706 // Compute attributes.
9707 PropertyAttributes attributes = NONE;
9708 if (args.length() == 5) {
9709 CONVERT_CHECKED(Smi, attrs, args[4]);
9710 int value = attrs->value();
9711 // Only attribute bits should be set.
9712 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
9713 attributes = static_cast<PropertyAttributes>(value);
9714 }
9715
9716 CONVERT_CHECKED(JSObject, obj, args[0]);
9717 CONVERT_CHECKED(String, name, args[1]);
9718 CONVERT_CHECKED(Smi, flag, args[2]);
9719 CONVERT_CHECKED(JSFunction, fun, args[3]);
9720 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
9721}
9722
9723
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009724RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009725 ASSERT(args.length() == 3);
9726 CONVERT_CHECKED(JSObject, obj, args[0]);
9727 CONVERT_CHECKED(String, name, args[1]);
9728 CONVERT_CHECKED(Smi, flag, args[2]);
9729 return obj->LookupAccessor(name, flag->value() == 0);
9730}
9731
9732
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009733#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009734RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009735 ASSERT(args.length() == 0);
9736 return Execution::DebugBreakHelper();
9737}
9738
9739
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009740// Helper functions for wrapping and unwrapping stack frame ids.
9741static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009742 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009743 return Smi::FromInt(id >> 2);
9744}
9745
9746
9747static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
9748 return static_cast<StackFrame::Id>(wrapped->value() << 2);
9749}
9750
9751
9752// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00009753// args[0]: debug event listener function to set or null or undefined for
9754// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009755// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009756RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009757 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009758 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
9759 args[0]->IsUndefined() ||
9760 args[0]->IsNull());
9761 Handle<Object> callback = args.at<Object>(0);
9762 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009763 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009764
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009765 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009766}
9767
9768
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009769RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +00009770 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009771 isolate->stack_guard()->DebugBreak();
9772 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009773}
9774
9775
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009776static MaybeObject* DebugLookupResultValue(Heap* heap,
9777 Object* receiver,
9778 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009779 LookupResult* result,
9780 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009781 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009782 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009783 case NORMAL:
9784 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009785 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009786 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009787 }
9788 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009789 case FIELD:
9790 value =
9791 JSObject::cast(
9792 result->holder())->FastPropertyAt(result->GetFieldIndex());
9793 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009794 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009795 }
9796 return value;
9797 case CONSTANT_FUNCTION:
9798 return result->GetConstantFunction();
9799 case CALLBACKS: {
9800 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00009801 if (structure->IsForeign() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009802 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009803 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009804 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009805 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009806 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009807 maybe_value = heap->isolate()->pending_exception();
9808 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009809 if (caught_exception != NULL) {
9810 *caught_exception = true;
9811 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009812 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009813 }
9814 return value;
9815 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009816 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009817 }
9818 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009819 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009820 case MAP_TRANSITION:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009821 case EXTERNAL_ARRAY_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009822 case CONSTANT_TRANSITION:
9823 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009824 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009825 default:
9826 UNREACHABLE();
9827 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009828 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009829 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009830}
9831
9832
ager@chromium.org32912102009-01-16 10:38:43 +00009833// Get debugger related details for an object property.
9834// args[0]: object holding property
9835// args[1]: name of the property
9836//
9837// The array returned contains the following information:
9838// 0: Property value
9839// 1: Property details
9840// 2: Property value is exception
9841// 3: Getter function if defined
9842// 4: Setter function if defined
9843// Items 2-4 are only filled if the property has either a getter or a setter
9844// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009845RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009846 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009847
9848 ASSERT(args.length() == 2);
9849
9850 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9851 CONVERT_ARG_CHECKED(String, name, 1);
9852
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009853 // Make sure to set the current context to the context before the debugger was
9854 // entered (if the debugger is entered). The reason for switching context here
9855 // is that for some property lookups (accessors and interceptors) callbacks
9856 // into the embedding application can occour, and the embedding application
9857 // could have the assumption that its own global context is the current
9858 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009859 SaveContext save(isolate);
9860 if (isolate->debug()->InDebugger()) {
9861 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009862 }
9863
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009864 // Skip the global proxy as it has no properties and always delegates to the
9865 // real global object.
9866 if (obj->IsJSGlobalProxy()) {
9867 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
9868 }
9869
9870
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009871 // Check if the name is trivially convertible to an index and get the element
9872 // if so.
9873 uint32_t index;
9874 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009875 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009876 Object* element_or_char;
9877 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009878 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009879 if (!maybe_element_or_char->ToObject(&element_or_char)) {
9880 return maybe_element_or_char;
9881 }
9882 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009883 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009884 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009885 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009886 }
9887
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009888 // Find the number of objects making up this.
9889 int length = LocalPrototypeChainLength(*obj);
9890
9891 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009892 Handle<JSObject> jsproto = obj;
9893 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009894 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009895 jsproto->LocalLookup(*name, &result);
9896 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009897 // LookupResult is not GC safe as it holds raw object pointers.
9898 // GC can happen later in this code so put the required fields into
9899 // local variables using handles when required for later use.
9900 PropertyType result_type = result.type();
9901 Handle<Object> result_callback_obj;
9902 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009903 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
9904 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009905 }
9906 Smi* property_details = result.GetPropertyDetails().AsSmi();
9907 // DebugLookupResultValue can cause GC so details from LookupResult needs
9908 // to be copied to handles before this.
9909 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009910 Object* raw_value;
9911 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009912 DebugLookupResultValue(isolate->heap(), *obj, *name,
9913 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009914 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
9915 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009916 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009917
9918 // If the callback object is a fixed array then it contains JavaScript
9919 // getter and/or setter.
9920 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
9921 result_callback_obj->IsFixedArray();
9922 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009923 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009924 details->set(0, *value);
9925 details->set(1, property_details);
9926 if (hasJavaScriptAccessors) {
9927 details->set(2,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009928 caught_exception ? isolate->heap()->true_value()
9929 : isolate->heap()->false_value());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009930 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
9931 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
9932 }
9933
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009934 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009935 }
9936 if (i < length - 1) {
9937 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
9938 }
9939 }
9940
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009941 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009942}
9943
9944
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009945RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009946 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009947
9948 ASSERT(args.length() == 2);
9949
9950 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9951 CONVERT_ARG_CHECKED(String, name, 1);
9952
9953 LookupResult result;
9954 obj->Lookup(*name, &result);
9955 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009956 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009957 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009958 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009959}
9960
9961
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009962// Return the property type calculated from the property details.
9963// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009964RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009965 ASSERT(args.length() == 1);
9966 CONVERT_CHECKED(Smi, details, args[0]);
9967 PropertyType type = PropertyDetails(details).type();
9968 return Smi::FromInt(static_cast<int>(type));
9969}
9970
9971
9972// Return the property attribute calculated from the property details.
9973// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009974RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009975 ASSERT(args.length() == 1);
9976 CONVERT_CHECKED(Smi, details, args[0]);
9977 PropertyAttributes attributes = PropertyDetails(details).attributes();
9978 return Smi::FromInt(static_cast<int>(attributes));
9979}
9980
9981
9982// Return the property insertion index calculated from the property details.
9983// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009984RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009985 ASSERT(args.length() == 1);
9986 CONVERT_CHECKED(Smi, details, args[0]);
9987 int index = PropertyDetails(details).index();
9988 return Smi::FromInt(index);
9989}
9990
9991
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009992// Return property value from named interceptor.
9993// args[0]: object
9994// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009995RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009996 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009997 ASSERT(args.length() == 2);
9998 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9999 RUNTIME_ASSERT(obj->HasNamedInterceptor());
10000 CONVERT_ARG_CHECKED(String, name, 1);
10001
10002 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010003 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010004}
10005
10006
10007// Return element value from indexed interceptor.
10008// args[0]: object
10009// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010010RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010011 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010012 ASSERT(args.length() == 2);
10013 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10014 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10015 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10016
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010017 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010018}
10019
10020
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010021RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010022 ASSERT(args.length() >= 1);
10023 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010024 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010025 if (isolate->debug()->break_id() == 0 ||
10026 break_id != isolate->debug()->break_id()) {
10027 return isolate->Throw(
10028 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010029 }
10030
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010031 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010032}
10033
10034
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010035RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010036 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010037 ASSERT(args.length() == 1);
10038
10039 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010040 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010041 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10042 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010043 if (!maybe_result->ToObject(&result)) return maybe_result;
10044 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010045
10046 // Count all frames which are relevant to debugging stack trace.
10047 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010048 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010049 if (id == StackFrame::NO_ID) {
10050 // If there is no JavaScript stack frame count is 0.
10051 return Smi::FromInt(0);
10052 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010053
10054 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10055 n += it.frame()->GetInlineCount();
10056 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010057 return Smi::FromInt(n);
10058}
10059
10060
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010061class FrameInspector {
10062 public:
10063 FrameInspector(JavaScriptFrame* frame,
10064 int inlined_frame_index,
10065 Isolate* isolate)
10066 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10067 // Calculate the deoptimized frame.
10068 if (frame->is_optimized()) {
10069 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
10070 frame, inlined_frame_index, isolate);
10071 }
10072 has_adapted_arguments_ = frame_->has_adapted_arguments();
10073 is_optimized_ = frame_->is_optimized();
10074 }
10075
10076 ~FrameInspector() {
10077 // Get rid of the calculated deoptimized frame if any.
10078 if (deoptimized_frame_ != NULL) {
10079 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10080 isolate_);
10081 }
10082 }
10083
10084 int GetParametersCount() {
10085 return is_optimized_
10086 ? deoptimized_frame_->parameters_count()
10087 : frame_->ComputeParametersCount();
10088 }
10089 int expression_count() { return deoptimized_frame_->expression_count(); }
10090 Object* GetFunction() {
10091 return is_optimized_
10092 ? deoptimized_frame_->GetFunction()
10093 : frame_->function();
10094 }
10095 Object* GetParameter(int index) {
10096 return is_optimized_
10097 ? deoptimized_frame_->GetParameter(index)
10098 : frame_->GetParameter(index);
10099 }
10100 Object* GetExpression(int index) {
10101 return is_optimized_
10102 ? deoptimized_frame_->GetExpression(index)
10103 : frame_->GetExpression(index);
10104 }
10105
10106 // To inspect all the provided arguments the frame might need to be
10107 // replaced with the arguments frame.
10108 void SetArgumentsFrame(JavaScriptFrame* frame) {
10109 ASSERT(has_adapted_arguments_);
10110 frame_ = frame;
10111 is_optimized_ = frame_->is_optimized();
10112 ASSERT(!is_optimized_);
10113 }
10114
10115 private:
10116 JavaScriptFrame* frame_;
10117 DeoptimizedFrameInfo* deoptimized_frame_;
10118 Isolate* isolate_;
10119 bool is_optimized_;
10120 bool has_adapted_arguments_;
10121
10122 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10123};
10124
10125
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010126static const int kFrameDetailsFrameIdIndex = 0;
10127static const int kFrameDetailsReceiverIndex = 1;
10128static const int kFrameDetailsFunctionIndex = 2;
10129static const int kFrameDetailsArgumentCountIndex = 3;
10130static const int kFrameDetailsLocalCountIndex = 4;
10131static const int kFrameDetailsSourcePositionIndex = 5;
10132static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010133static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010134static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010135static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010136
10137// Return an array with frame details
10138// args[0]: number: break id
10139// args[1]: number: frame index
10140//
10141// The array returned contains the following information:
10142// 0: Frame id
10143// 1: Receiver
10144// 2: Function
10145// 3: Argument count
10146// 4: Local count
10147// 5: Source position
10148// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010149// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010150// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010151// Arguments name, value
10152// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010153// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010154RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010155 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010156 ASSERT(args.length() == 2);
10157
10158 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010159 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010160 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10161 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010162 if (!maybe_check->ToObject(&check)) return maybe_check;
10163 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010164 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010165 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010166
10167 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010168 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010169 if (id == StackFrame::NO_ID) {
10170 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010171 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010172 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010173
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010174 int inlined_frame_index = 0; // Inlined frame index in optimized frame.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010175
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010176 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010177 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010178 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010179 if (index < count + it.frame()->GetInlineCount()) break;
10180 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010181 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010182 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010183
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010184 if (it.frame()->is_optimized()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010185 inlined_frame_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010186 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010187 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010188 FrameInspector frame_inspector(it.frame(), inlined_frame_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010189
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010190 // Traverse the saved contexts chain to find the active context for the
10191 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010192 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010193 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010194 save = save->prev();
10195 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010196 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010197
10198 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010199 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010200
10201 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010202 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010203 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010204
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010205 // Check for constructor frame. Inlined frames cannot be construct calls.
10206 bool inlined_frame =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010207 it.frame()->is_optimized() && inlined_frame_index != 0;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010208 bool constructor = !inlined_frame && it.frame()->IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010209
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010210 // Get scope info and read from it for local variable information.
10211 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010212 Handle<SharedFunctionInfo> shared(function->shared());
10213 Handle<SerializedScopeInfo> scope_info(shared->scope_info());
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010214 ASSERT(*scope_info != SerializedScopeInfo::Empty());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010215 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010216
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010217 // Get the locals names and values into a temporary array.
10218 //
10219 // TODO(1240907): Hide compiler-introduced stack variables
10220 // (e.g. .result)? For users of the debugger, they will probably be
10221 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010222 Handle<FixedArray> locals =
10223 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010224
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010225 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010226 int i = 0;
10227 for (; i < info.number_of_stack_slots(); ++i) {
10228 // Use the value from the stack.
10229 locals->set(i * 2, *info.LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010230 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010231 }
10232 if (i < info.NumberOfLocals()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010233 // Get the context containing declarations.
10234 Handle<Context> context(
10235 Context::cast(it.frame()->context())->declaration_context());
10236 for (; i < info.NumberOfLocals(); ++i) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010237 Handle<String> name = info.LocalName(i);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010238 locals->set(i * 2, *name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010239 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010240 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010241 }
10242 }
10243
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010244 // Check whether this frame is positioned at return. If not top
10245 // frame or if the frame is optimized it cannot be at a return.
10246 bool at_return = false;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010247 if (!it.frame()->is_optimized() && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010248 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010249 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010250
10251 // If positioned just before return find the value to be returned and add it
10252 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010253 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010254 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010255 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010256 Address internal_frame_sp = NULL;
10257 while (!it2.done()) {
10258 if (it2.frame()->is_internal()) {
10259 internal_frame_sp = it2.frame()->sp();
10260 } else {
10261 if (it2.frame()->is_java_script()) {
10262 if (it2.frame()->id() == it.frame()->id()) {
10263 // The internal frame just before the JavaScript frame contains the
10264 // value to return on top. A debug break at return will create an
10265 // internal frame to store the return value (eax/rax/r0) before
10266 // entering the debug break exit frame.
10267 if (internal_frame_sp != NULL) {
10268 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010269 Handle<Object>(Memory::Object_at(internal_frame_sp),
10270 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010271 break;
10272 }
10273 }
10274 }
10275
10276 // Indicate that the previous frame was not an internal frame.
10277 internal_frame_sp = NULL;
10278 }
10279 it2.Advance();
10280 }
10281 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010282
10283 // Now advance to the arguments adapter frame (if any). It contains all
10284 // the provided parameters whereas the function frame always have the number
10285 // of arguments matching the functions parameters. The rest of the
10286 // information (except for what is collected above) is the same.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010287 if (it.frame()->has_adapted_arguments()) {
10288 it.AdvanceToArgumentsFrame();
10289 frame_inspector.SetArgumentsFrame(it.frame());
10290 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010291
10292 // Find the number of arguments to fill. At least fill the number of
10293 // parameters for the function and fill more if more parameters are provided.
10294 int argument_count = info.number_of_parameters();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010295 if (argument_count < frame_inspector.GetParametersCount()) {
10296 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010297 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010298#ifdef DEBUG
10299 if (it.frame()->is_optimized()) {
10300 ASSERT_EQ(argument_count, frame_inspector.GetParametersCount());
10301 }
10302#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010303
10304 // Calculate the size of the result.
10305 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010306 2 * (argument_count + info.NumberOfLocals()) +
10307 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010308 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010309
10310 // Add the frame id.
10311 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10312
10313 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010314 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010315
10316 // Add the arguments count.
10317 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10318
10319 // Add the locals count
10320 details->set(kFrameDetailsLocalCountIndex,
10321 Smi::FromInt(info.NumberOfLocals()));
10322
10323 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010324 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010325 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10326 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010327 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010328 }
10329
10330 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010331 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010332
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010333 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010334 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010335
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010336 // Add flags to indicate information on whether this frame is
10337 // bit 0: invoked in the debugger context.
10338 // bit 1: optimized frame.
10339 // bit 2: inlined in optimized frame
10340 int flags = 0;
10341 if (*save->context() == *isolate->debug()->debug_context()) {
10342 flags |= 1 << 0;
10343 }
10344 if (it.frame()->is_optimized()) {
10345 flags |= 1 << 1;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010346 flags |= inlined_frame_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010347 }
10348 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010349
10350 // Fill the dynamic part.
10351 int details_index = kFrameDetailsFirstDynamicIndex;
10352
10353 // Add arguments name and value.
10354 for (int i = 0; i < argument_count; i++) {
10355 // Name of the argument.
10356 if (i < info.number_of_parameters()) {
10357 details->set(details_index++, *info.parameter_name(i));
10358 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010359 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010360 }
10361
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010362 // Parameter value.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010363 if (i < it.frame()->ComputeParametersCount()) {
10364 // Get the value from the stack.
10365 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010366 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010367 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010368 }
10369 }
10370
10371 // Add locals name and value from the temporary copy from the function frame.
10372 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
10373 details->set(details_index++, locals->get(i));
10374 }
10375
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010376 // Add the value being returned.
10377 if (at_return) {
10378 details->set(details_index++, *return_value);
10379 }
10380
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010381 // Add the receiver (same as in function frame).
10382 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10383 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010384 Handle<Object> receiver(it.frame()->receiver(), isolate);
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010385 if (!receiver->IsJSObject() && !shared->strict_mode() && !shared->native()) {
10386 // If the receiver is not a JSObject and the function is not a
10387 // builtin or strict-mode we have hit an optimization where a
10388 // value object is not converted into a wrapped JS objects. To
10389 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010390 // by creating correct wrapper object based on the calling frame's
10391 // global context.
10392 it.Advance();
10393 Handle<Context> calling_frames_global_context(
10394 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010395 receiver =
10396 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010397 }
10398 details->set(kFrameDetailsReceiverIndex, *receiver);
10399
10400 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010401 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010402}
10403
10404
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010405// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010406static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010407 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010408 Handle<SerializedScopeInfo> serialized_scope_info,
10409 ScopeInfo<>& scope_info,
10410 Handle<Context> context,
10411 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010412 // Fill all context locals to the context extension.
10413 for (int i = Context::MIN_CONTEXT_SLOTS;
10414 i < scope_info.number_of_context_slots();
10415 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +000010416 int context_index = serialized_scope_info->ContextSlotIndex(
10417 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010418
whesse@chromium.org7b260152011-06-20 15:33:18 +000010419 RETURN_IF_EMPTY_HANDLE_VALUE(
10420 isolate,
10421 SetProperty(scope_object,
10422 scope_info.context_slot_name(i),
10423 Handle<Object>(context->get(context_index), isolate),
10424 NONE,
10425 kNonStrictMode),
10426 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010427 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010428
10429 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010430}
10431
10432
10433// Create a plain JSObject which materializes the local scope for the specified
10434// frame.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010435static Handle<JSObject> MaterializeLocalScope(
10436 Isolate* isolate,
10437 JavaScriptFrame* frame,
10438 int inlined_frame_index) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010439 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010440 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010441 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10442 ScopeInfo<> scope_info(*serialized_scope_info);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010443 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010444
10445 // Allocate and initialize a JSObject with all the arguments, stack locals
10446 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010447 Handle<JSObject> local_scope =
10448 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010449
10450 // First fill all parameters.
10451 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010452 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010453 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010454 SetProperty(local_scope,
10455 scope_info.parameter_name(i),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010456 Handle<Object>(frame_inspector.GetParameter(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010457 NONE,
10458 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010459 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010460 }
10461
10462 // Second fill all stack locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010463 for (int i = 0; i < scope_info.number_of_stack_slots(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010464 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010465 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010466 SetProperty(local_scope,
10467 scope_info.stack_slot_name(i),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010468 Handle<Object>(frame_inspector.GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010469 NONE,
10470 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010471 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010472 }
10473
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010474 if (scope_info.number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
10475 // Third fill all context locals.
10476 Handle<Context> frame_context(Context::cast(frame->context()));
10477 Handle<Context> function_context(frame_context->declaration_context());
10478 if (!CopyContextLocalsToScopeObject(isolate,
10479 serialized_scope_info, scope_info,
10480 function_context, local_scope)) {
10481 return Handle<JSObject>();
10482 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010483
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010484 // Finally copy any properties from the function context extension.
10485 // These will be variables introduced by eval.
10486 if (function_context->closure() == *function) {
10487 if (function_context->has_extension() &&
10488 !function_context->IsGlobalContext()) {
10489 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
10490 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
10491 for (int i = 0; i < keys->length(); i++) {
10492 // Names of variables introduced by eval are strings.
10493 ASSERT(keys->get(i)->IsString());
10494 Handle<String> key(String::cast(keys->get(i)));
10495 RETURN_IF_EMPTY_HANDLE_VALUE(
10496 isolate,
10497 SetProperty(local_scope,
10498 key,
10499 GetProperty(ext, key),
10500 NONE,
10501 kNonStrictMode),
10502 Handle<JSObject>());
10503 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010504 }
10505 }
10506 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010507
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010508 return local_scope;
10509}
10510
10511
10512// Create a plain JSObject which materializes the closure content for the
10513// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010514static Handle<JSObject> MaterializeClosure(Isolate* isolate,
10515 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010516 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010517
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010518 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010519 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10520 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010521
10522 // Allocate and initialize a JSObject with all the content of theis function
10523 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010524 Handle<JSObject> closure_scope =
10525 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010526
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010527 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010528 if (!CopyContextLocalsToScopeObject(isolate,
10529 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010530 context, closure_scope)) {
10531 return Handle<JSObject>();
10532 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010533
10534 // Finally copy any properties from the function context extension. This will
10535 // be variables introduced by eval.
10536 if (context->has_extension()) {
10537 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010538 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010539 for (int i = 0; i < keys->length(); i++) {
10540 // Names of variables introduced by eval are strings.
10541 ASSERT(keys->get(i)->IsString());
10542 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010543 RETURN_IF_EMPTY_HANDLE_VALUE(
10544 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010545 SetProperty(closure_scope,
10546 key,
10547 GetProperty(ext, key),
10548 NONE,
10549 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010550 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010551 }
10552 }
10553
10554 return closure_scope;
10555}
10556
10557
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010558// Create a plain JSObject which materializes the scope for the specified
10559// catch context.
10560static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
10561 Handle<Context> context) {
10562 ASSERT(context->IsCatchContext());
10563 Handle<String> name(String::cast(context->extension()));
10564 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
10565 Handle<JSObject> catch_scope =
10566 isolate->factory()->NewJSObject(isolate->object_function());
10567 RETURN_IF_EMPTY_HANDLE_VALUE(
10568 isolate,
10569 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
10570 Handle<JSObject>());
10571 return catch_scope;
10572}
10573
10574
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010575// Iterate over the actual scopes visible from a stack frame. All scopes are
10576// backed by an actual context except the local scope, which is inserted
10577// "artifically" in the context chain.
10578class ScopeIterator {
10579 public:
10580 enum ScopeType {
10581 ScopeTypeGlobal = 0,
10582 ScopeTypeLocal,
10583 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010584 ScopeTypeClosure,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010585 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010586 };
10587
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010588 ScopeIterator(Isolate* isolate,
10589 JavaScriptFrame* frame,
10590 int inlined_frame_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010591 : isolate_(isolate),
10592 frame_(frame),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010593 inlined_frame_index_(inlined_frame_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010594 function_(JSFunction::cast(frame->function())),
10595 context_(Context::cast(frame->context())),
10596 local_done_(false),
10597 at_local_(false) {
10598
10599 // Check whether the first scope is actually a local scope.
10600 if (context_->IsGlobalContext()) {
10601 // If there is a stack slot for .result then this local scope has been
10602 // created for evaluating top level code and it is not a real local scope.
10603 // Checking for the existence of .result seems fragile, but the scope info
10604 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +000010605 int index = function_->shared()->scope_info()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010606 StackSlotIndex(isolate_->heap()->result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010607 at_local_ = index < 0;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010608 } else if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010609 at_local_ = true;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010610 } else if (context_->closure() != *function_) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010611 // The context_ is a with or catch block from the outer function.
10612 ASSERT(context_->IsWithContext() || context_->IsCatchContext());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010613 at_local_ = true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010614 }
10615 }
10616
10617 // More scopes?
10618 bool Done() { return context_.is_null(); }
10619
10620 // Move to the next scope.
10621 void Next() {
10622 // If at a local scope mark the local scope as passed.
10623 if (at_local_) {
10624 at_local_ = false;
10625 local_done_ = true;
10626
10627 // If the current context is not associated with the local scope the
10628 // current context is the next real scope, so don't move to the next
10629 // context in this case.
10630 if (context_->closure() != *function_) {
10631 return;
10632 }
10633 }
10634
10635 // The global scope is always the last in the chain.
10636 if (context_->IsGlobalContext()) {
10637 context_ = Handle<Context>();
10638 return;
10639 }
10640
10641 // Move to the next context.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010642 context_ = Handle<Context>(context_->previous(), isolate_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010643
10644 // If passing the local scope indicate that the current scope is now the
10645 // local scope.
10646 if (!local_done_ &&
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010647 (context_->IsGlobalContext() || context_->IsFunctionContext())) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010648 at_local_ = true;
10649 }
10650 }
10651
10652 // Return the type of the current scope.
10653 int Type() {
10654 if (at_local_) {
10655 return ScopeTypeLocal;
10656 }
10657 if (context_->IsGlobalContext()) {
10658 ASSERT(context_->global()->IsGlobalObject());
10659 return ScopeTypeGlobal;
10660 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010661 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010662 return ScopeTypeClosure;
10663 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010664 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010665 return ScopeTypeCatch;
10666 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010667 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010668 return ScopeTypeWith;
10669 }
10670
10671 // Return the JavaScript object with the content of the current scope.
10672 Handle<JSObject> ScopeObject() {
10673 switch (Type()) {
10674 case ScopeIterator::ScopeTypeGlobal:
10675 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010676 case ScopeIterator::ScopeTypeLocal:
10677 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010678 return MaterializeLocalScope(isolate_, frame_, inlined_frame_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010679 case ScopeIterator::ScopeTypeWith:
10680 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010681 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
10682 case ScopeIterator::ScopeTypeCatch:
10683 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010684 case ScopeIterator::ScopeTypeClosure:
10685 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010686 return MaterializeClosure(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010687 }
10688 UNREACHABLE();
10689 return Handle<JSObject>();
10690 }
10691
10692 // Return the context for this scope. For the local context there might not
10693 // be an actual context.
10694 Handle<Context> CurrentContext() {
10695 if (at_local_ && context_->closure() != *function_) {
10696 return Handle<Context>();
10697 }
10698 return context_;
10699 }
10700
10701#ifdef DEBUG
10702 // Debug print of the content of the current scope.
10703 void DebugPrint() {
10704 switch (Type()) {
10705 case ScopeIterator::ScopeTypeGlobal:
10706 PrintF("Global:\n");
10707 CurrentContext()->Print();
10708 break;
10709
10710 case ScopeIterator::ScopeTypeLocal: {
10711 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010712 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010713 scope_info.Print();
10714 if (!CurrentContext().is_null()) {
10715 CurrentContext()->Print();
10716 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010717 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010718 if (extension->IsJSContextExtensionObject()) {
10719 extension->Print();
10720 }
10721 }
10722 }
10723 break;
10724 }
10725
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010726 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010727 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010728 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010729 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010730
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010731 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000010732 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010733 CurrentContext()->extension()->Print();
10734 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000010735 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000010736
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010737 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010738 PrintF("Closure:\n");
10739 CurrentContext()->Print();
10740 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010741 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010742 if (extension->IsJSContextExtensionObject()) {
10743 extension->Print();
10744 }
10745 }
10746 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010747
10748 default:
10749 UNREACHABLE();
10750 }
10751 PrintF("\n");
10752 }
10753#endif
10754
10755 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010756 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010757 JavaScriptFrame* frame_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010758 int inlined_frame_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010759 Handle<JSFunction> function_;
10760 Handle<Context> context_;
10761 bool local_done_;
10762 bool at_local_;
10763
10764 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
10765};
10766
10767
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010768RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010769 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010770 ASSERT(args.length() == 2);
10771
10772 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010773 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010774 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10775 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010776 if (!maybe_check->ToObject(&check)) return maybe_check;
10777 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010778 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10779
10780 // Get the frame where the debugging is performed.
10781 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010782 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010783 JavaScriptFrame* frame = it.frame();
10784
10785 // Count the visible scopes.
10786 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010787 for (ScopeIterator it(isolate, frame, 0);
10788 !it.Done();
10789 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010790 n++;
10791 }
10792
10793 return Smi::FromInt(n);
10794}
10795
10796
10797static const int kScopeDetailsTypeIndex = 0;
10798static const int kScopeDetailsObjectIndex = 1;
10799static const int kScopeDetailsSize = 2;
10800
10801// Return an array with scope details
10802// args[0]: number: break id
10803// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010804// args[2]: number: inlined frame index
10805// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010806//
10807// The array returned contains the following information:
10808// 0: Scope type
10809// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010810RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010811 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010812 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010813
10814 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010815 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010816 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10817 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010818 if (!maybe_check->ToObject(&check)) return maybe_check;
10819 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010820 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010821 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
10822 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010823
10824 // Get the frame where the debugging is performed.
10825 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010826 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010827 JavaScriptFrame* frame = frame_it.frame();
10828
10829 // Find the requested scope.
10830 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010831 ScopeIterator it(isolate, frame, inlined_frame_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010832 for (; !it.Done() && n < index; it.Next()) {
10833 n++;
10834 }
10835 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010836 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010837 }
10838
10839 // Calculate the size of the result.
10840 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010841 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010842
10843 // Fill in scope details.
10844 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010845 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010846 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010847 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010848
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010849 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010850}
10851
10852
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010853RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010854 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010855 ASSERT(args.length() == 0);
10856
10857#ifdef DEBUG
10858 // Print the scopes for the top frame.
10859 StackFrameLocator locator;
10860 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010861 for (ScopeIterator it(isolate, frame, 0);
10862 !it.Done();
10863 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010864 it.DebugPrint();
10865 }
10866#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010867 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010868}
10869
10870
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010871RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010872 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010873 ASSERT(args.length() == 1);
10874
10875 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010876 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010877 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10878 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010879 if (!maybe_result->ToObject(&result)) return maybe_result;
10880 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010881
10882 // Count all archived V8 threads.
10883 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010884 for (ThreadState* thread =
10885 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010886 thread != NULL;
10887 thread = thread->Next()) {
10888 n++;
10889 }
10890
10891 // Total number of threads is current thread and archived threads.
10892 return Smi::FromInt(n + 1);
10893}
10894
10895
10896static const int kThreadDetailsCurrentThreadIndex = 0;
10897static const int kThreadDetailsThreadIdIndex = 1;
10898static const int kThreadDetailsSize = 2;
10899
10900// Return an array with thread details
10901// args[0]: number: break id
10902// args[1]: number: thread index
10903//
10904// The array returned contains the following information:
10905// 0: Is current thread?
10906// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010907RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010908 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010909 ASSERT(args.length() == 2);
10910
10911 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010912 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010913 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10914 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010915 if (!maybe_check->ToObject(&check)) return maybe_check;
10916 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010917 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
10918
10919 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010920 Handle<FixedArray> details =
10921 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010922
10923 // Thread index 0 is current thread.
10924 if (index == 0) {
10925 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010926 details->set(kThreadDetailsCurrentThreadIndex,
10927 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010928 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010929 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010930 } else {
10931 // Find the thread with the requested index.
10932 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010933 ThreadState* thread =
10934 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010935 while (index != n && thread != NULL) {
10936 thread = thread->Next();
10937 n++;
10938 }
10939 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010940 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010941 }
10942
10943 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010944 details->set(kThreadDetailsCurrentThreadIndex,
10945 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010946 details->set(kThreadDetailsThreadIdIndex,
10947 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010948 }
10949
10950 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010951 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010952}
10953
10954
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010955// Sets the disable break state
10956// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010957RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010958 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010959 ASSERT(args.length() == 1);
10960 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010961 isolate->debug()->set_disable_break(disable_break);
10962 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010963}
10964
10965
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010966RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010967 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010968 ASSERT(args.length() == 1);
10969
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010970 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10971 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010972 // Find the number of break points
10973 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010974 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010975 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010976 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010977 Handle<FixedArray>::cast(break_locations));
10978}
10979
10980
10981// Set a break point in a function
10982// args[0]: function
10983// args[1]: number: break source position (within the function source)
10984// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010985RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010986 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010987 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010988 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10989 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010990 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10991 RUNTIME_ASSERT(source_position >= 0);
10992 Handle<Object> break_point_object_arg = args.at<Object>(2);
10993
10994 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010995 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
10996 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010997
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010998 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010999}
11000
11001
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011002Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11003 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011004 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011005 // Iterate the heap looking for SharedFunctionInfo generated from the
11006 // script. The inner most SharedFunctionInfo containing the source position
11007 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011008 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011009 // which is found is not compiled it is compiled and the heap is iterated
11010 // again as the compilation might create inner functions from the newly
11011 // compiled function and the actual requested break point might be in one of
11012 // these functions.
11013 bool done = false;
11014 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011015 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011016 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011017 while (!done) {
11018 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011019 for (HeapObject* obj = iterator.next();
11020 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011021 if (obj->IsSharedFunctionInfo()) {
11022 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11023 if (shared->script() == *script) {
11024 // If the SharedFunctionInfo found has the requested script data and
11025 // contains the source position it is a candidate.
11026 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +000011027 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011028 start_position = shared->start_position();
11029 }
11030 if (start_position <= position &&
11031 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +000011032 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011033 // candidate this is the new candidate.
11034 if (target.is_null()) {
11035 target_start_position = start_position;
11036 target = shared;
11037 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011038 if (target_start_position == start_position &&
11039 shared->end_position() == target->end_position()) {
11040 // If a top-level function contain only one function
11041 // declartion the source for the top-level and the function is
11042 // the same. In that case prefer the non top-level function.
11043 if (!shared->is_toplevel()) {
11044 target_start_position = start_position;
11045 target = shared;
11046 }
11047 } else if (target_start_position <= start_position &&
11048 shared->end_position() <= target->end_position()) {
11049 // This containment check includes equality as a function inside
11050 // a top-level function can share either start or end position
11051 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011052 target_start_position = start_position;
11053 target = shared;
11054 }
11055 }
11056 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011057 }
11058 }
11059 }
11060
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011061 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011062 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011063 }
11064
11065 // If the candidate found is compiled we are done. NOTE: when lazy
11066 // compilation of inner functions is introduced some additional checking
11067 // needs to be done here to compile inner functions.
11068 done = target->is_compiled();
11069 if (!done) {
11070 // If the candidate is not compiled compile it to reveal any inner
11071 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011072 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011073 }
11074 }
11075
11076 return *target;
11077}
11078
11079
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011080// Changes the state of a break point in a script and returns source position
11081// where break point was set. NOTE: Regarding performance see the NOTE for
11082// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011083// args[0]: script to set break point in
11084// args[1]: number: break source position (within the script source)
11085// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011086RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011087 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011088 ASSERT(args.length() == 3);
11089 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
11090 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11091 RUNTIME_ASSERT(source_position >= 0);
11092 Handle<Object> break_point_object_arg = args.at<Object>(2);
11093
11094 // Get the script from the script wrapper.
11095 RUNTIME_ASSERT(wrapper->value()->IsScript());
11096 Handle<Script> script(Script::cast(wrapper->value()));
11097
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011098 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011099 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011100 if (!result->IsUndefined()) {
11101 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11102 // Find position within function. The script position might be before the
11103 // source position of the first function.
11104 int position;
11105 if (shared->start_position() > source_position) {
11106 position = 0;
11107 } else {
11108 position = source_position - shared->start_position();
11109 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011110 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011111 position += shared->start_position();
11112 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011113 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011114 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011115}
11116
11117
11118// Clear a break point
11119// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011120RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011121 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011122 ASSERT(args.length() == 1);
11123 Handle<Object> break_point_object_arg = args.at<Object>(0);
11124
11125 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011126 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011127
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011128 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011129}
11130
11131
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011132// Change the state of break on exceptions.
11133// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11134// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011135RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011136 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011137 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011138 RUNTIME_ASSERT(args[0]->IsNumber());
11139 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011140
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011141 // If the number doesn't match an enum value, the ChangeBreakOnException
11142 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011143 ExceptionBreakType type =
11144 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011145 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011146 isolate->debug()->ChangeBreakOnException(type, enable);
11147 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011148}
11149
11150
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011151// Returns the state of break on exceptions
11152// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011153RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011154 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011155 ASSERT(args.length() == 1);
11156 RUNTIME_ASSERT(args[0]->IsNumber());
11157
11158 ExceptionBreakType type =
11159 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011160 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011161 return Smi::FromInt(result);
11162}
11163
11164
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011165// Prepare for stepping
11166// args[0]: break id for checking execution state
11167// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011168// args[2]: number of times to perform the step, for step out it is the number
11169// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011170RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011171 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011172 ASSERT(args.length() == 3);
11173 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011174 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011175 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11176 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011177 if (!maybe_check->ToObject(&check)) return maybe_check;
11178 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011179 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011180 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011181 }
11182
11183 // Get the step action and check validity.
11184 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11185 if (step_action != StepIn &&
11186 step_action != StepNext &&
11187 step_action != StepOut &&
11188 step_action != StepInMin &&
11189 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011190 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011191 }
11192
11193 // Get the number of steps.
11194 int step_count = NumberToInt32(args[2]);
11195 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011196 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011197 }
11198
ager@chromium.orga1645e22009-09-09 19:27:10 +000011199 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011200 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011201
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011202 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011203 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11204 step_count);
11205 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011206}
11207
11208
11209// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011210RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011211 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011212 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011213 isolate->debug()->ClearStepping();
11214 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011215}
11216
11217
11218// Creates a copy of the with context chain. The copy of the context chain is
11219// is linked to the function context supplied.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011220static Handle<Context> CopyWithContextChain(Isolate* isolate,
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011221 Handle<JSFunction> function,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011222 Handle<Context> current,
11223 Handle<Context> base) {
11224 // At the end of the chain. Return the base context to link to.
11225 if (current->IsFunctionContext() || current->IsGlobalContext()) {
11226 return base;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011227 }
11228
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011229 // Recursively copy the with and catch contexts.
11230 HandleScope scope(isolate);
11231 Handle<Context> previous(current->previous());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011232 Handle<Context> new_previous =
11233 CopyWithContextChain(isolate, function, previous, base);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011234 Handle<Context> new_current;
11235 if (current->IsCatchContext()) {
11236 Handle<String> name(String::cast(current->extension()));
11237 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11238 new_current =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011239 isolate->factory()->NewCatchContext(function,
11240 new_previous,
11241 name,
11242 thrown_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011243 } else {
11244 Handle<JSObject> extension(JSObject::cast(current->extension()));
11245 new_current =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011246 isolate->factory()->NewWithContext(function, new_previous, extension);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011247 }
11248 return scope.CloseAndEscape(new_current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011249}
11250
11251
11252// Helper function to find or create the arguments object for
11253// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011254static Handle<Object> GetArgumentsObject(Isolate* isolate,
11255 JavaScriptFrame* frame,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011256 int inlined_frame_index,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011257 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000011258 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011259 const ScopeInfo<>* sinfo,
11260 Handle<Context> function_context) {
11261 // Try to find the value of 'arguments' to pass as parameter. If it is not
11262 // found (that is the debugged function does not reference 'arguments' and
11263 // does not support eval) then create an 'arguments' object.
11264 int index;
11265 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011266 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011267 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011268 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011269 }
11270 }
11271
11272 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011273 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
11274 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011275 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011276 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011277 }
11278 }
11279
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011280 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
11281
11282 int length = frame_inspector.GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011283 Handle<JSObject> arguments =
11284 isolate->factory()->NewArgumentsObject(function, length);
11285 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011286
11287 AssertNoAllocation no_gc;
11288 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011289 for (int i = 0; i < length; i++) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011290 array->set(i, frame_inspector.GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011291 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011292 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011293 return arguments;
11294}
11295
11296
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011297static const char kSourceStr[] =
11298 "(function(arguments,__source__){return eval(__source__);})";
11299
11300
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011301// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000011302// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011303// extension part has all the parameters and locals of the function on the
11304// stack frame. A function which calls eval with the code to evaluate is then
11305// compiled in this context and called in this context. As this context
11306// replaces the context of the function on the stack frame a new (empty)
11307// function is created as well to be used as the closure for the context.
11308// This function and the context acts as replacements for the function on the
11309// stack frame presenting the same view of the values of parameters and
11310// local variables as if the piece of JavaScript was evaluated at the point
11311// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011312RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011313 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011314
11315 // Check the execution state and decode arguments frame and source to be
11316 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011317 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011318 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011319 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11320 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011321 if (!maybe_check_result->ToObject(&check_result)) {
11322 return maybe_check_result;
11323 }
11324 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011325 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011326 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
11327 CONVERT_ARG_CHECKED(String, source, 3);
11328 CONVERT_BOOLEAN_CHECKED(disable_break, args[4]);
11329 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011330
11331 // Handle the processing of break.
11332 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011333
11334 // Get the frame where the debugging is performed.
11335 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011336 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011337 JavaScriptFrame* frame = it.frame();
11338 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000011339 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011340 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011341
11342 // Traverse the saved contexts chain to find the active context for the
11343 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011344 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000011345 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011346 save = save->prev();
11347 }
11348 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011349 SaveContext savex(isolate);
11350 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011351
11352 // Create the (empty) function replacing the function on the stack frame for
11353 // the purpose of evaluating in the context created below. It is important
11354 // that this function does not describe any parameters and local variables
11355 // in the context. If it does then this will cause problems with the lookup
11356 // in Context::Lookup, where context slots for parameters and local variables
11357 // are looked at before the extension object.
11358 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011359 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
11360 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011361 go_between->set_context(function->context());
11362#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011363 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011364 ASSERT(go_between_sinfo.number_of_parameters() == 0);
11365 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
11366#endif
11367
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011368 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011369 Handle<JSObject> local_scope = MaterializeLocalScope(
11370 isolate, frame, inlined_frame_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011371 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011372
11373 // Allocate a new context for the debug evaluation and set the extension
11374 // object build.
11375 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011376 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11377 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011378 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011379 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011380 Handle<Context> frame_context(Context::cast(frame->context()));
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011381 Handle<Context> function_context(frame_context->declaration_context());
11382 context = CopyWithContextChain(isolate, go_between, frame_context, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011383
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011384 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011385 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011386 context =
11387 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011388 }
11389
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011390 // Wrap the evaluation statement in a new function compiled in the newly
11391 // created context. The function has one parameter which has to be called
11392 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000011393 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011394 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011395
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011396 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011397 isolate->factory()->NewStringFromAscii(
11398 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011399
11400 // Currently, the eval code will be executed in non-strict mode,
11401 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011402 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000011403 Compiler::CompileEval(function_source,
11404 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011405 context->IsGlobalContext(),
11406 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011407 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011408 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011409 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011410
11411 // Invoke the result of the compilation to get the evaluation function.
11412 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011413 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011414 Handle<Object> evaluation_function =
11415 Execution::Call(compiled_function, receiver, 0, NULL,
11416 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011417 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011418
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011419 Handle<Object> arguments = GetArgumentsObject(isolate,
11420 frame, inlined_frame_index,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011421 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011422 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011423
11424 // Invoke the evaluation function and return the result.
11425 const int argc = 2;
11426 Object** argv[argc] = { arguments.location(),
11427 Handle<Object>::cast(source).location() };
11428 Handle<Object> result =
11429 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
11430 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011431 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011432
11433 // Skip the global proxy as it has no properties and always delegates to the
11434 // real global object.
11435 if (result->IsJSGlobalProxy()) {
11436 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
11437 }
11438
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011439 return *result;
11440}
11441
11442
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011443RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011444 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011445
11446 // Check the execution state and decode arguments frame and source to be
11447 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011448 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011449 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011450 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11451 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011452 if (!maybe_check_result->ToObject(&check_result)) {
11453 return maybe_check_result;
11454 }
11455 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011456 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011457 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011458 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011459
11460 // Handle the processing of break.
11461 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011462
11463 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011464 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011465 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011466 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011467 top = top->prev();
11468 }
11469 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011470 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011471 }
11472
11473 // Get the global context now set to the top context from before the
11474 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011475 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011476
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011477 bool is_global = true;
11478
11479 if (additional_context->IsJSObject()) {
11480 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011481 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
11482 isolate->factory()->empty_string(),
11483 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011484 go_between->set_context(*context);
11485 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011486 isolate->factory()->NewFunctionContext(
11487 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011488 context->set_extension(JSObject::cast(*additional_context));
11489 is_global = false;
11490 }
11491
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011492 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011493 // Currently, the eval code will be executed in non-strict mode,
11494 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011495 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011496 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011497 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011498 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011499 Handle<JSFunction>(
11500 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
11501 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011502
11503 // Invoke the result of the compilation to get the evaluation function.
11504 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011505 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011506 Handle<Object> result =
11507 Execution::Call(compiled_function, receiver, 0, NULL,
11508 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011509 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011510 return *result;
11511}
11512
11513
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011514RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011515 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011516 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011517
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011518 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011519 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011520
11521 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000011522 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000011523 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
11524 // Get the script wrapper in a local handle before calling GetScriptWrapper,
11525 // because using
11526 // instances->set(i, *GetScriptWrapper(script))
11527 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
11528 // already have deferenced the instances handle.
11529 Handle<JSValue> wrapper = GetScriptWrapper(script);
11530 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011531 }
11532
11533 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011534 Handle<JSObject> result =
11535 isolate->factory()->NewJSObject(isolate->array_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011536 Handle<JSArray>::cast(result)->SetContent(*instances);
11537 return *result;
11538}
11539
11540
11541// Helper function used by Runtime_DebugReferencedBy below.
11542static int DebugReferencedBy(JSObject* target,
11543 Object* instance_filter, int max_references,
11544 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011545 JSFunction* arguments_function) {
11546 NoHandleAllocation ha;
11547 AssertNoAllocation no_alloc;
11548
11549 // Iterate the heap.
11550 int count = 0;
11551 JSObject* last = NULL;
11552 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011553 HeapObject* heap_obj = NULL;
11554 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011555 (max_references == 0 || count < max_references)) {
11556 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011557 if (heap_obj->IsJSObject()) {
11558 // Skip context extension objects and argument arrays as these are
11559 // checked in the context of functions using them.
11560 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000011561 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011562 obj->map()->constructor() == arguments_function) {
11563 continue;
11564 }
11565
11566 // Check if the JS object has a reference to the object looked for.
11567 if (obj->ReferencesObject(target)) {
11568 // Check instance filter if supplied. This is normally used to avoid
11569 // references from mirror objects (see Runtime_IsInPrototypeChain).
11570 if (!instance_filter->IsUndefined()) {
11571 Object* V = obj;
11572 while (true) {
11573 Object* prototype = V->GetPrototype();
11574 if (prototype->IsNull()) {
11575 break;
11576 }
11577 if (instance_filter == prototype) {
11578 obj = NULL; // Don't add this object.
11579 break;
11580 }
11581 V = prototype;
11582 }
11583 }
11584
11585 if (obj != NULL) {
11586 // Valid reference found add to instance array if supplied an update
11587 // count.
11588 if (instances != NULL && count < instances_size) {
11589 instances->set(count, obj);
11590 }
11591 last = obj;
11592 count++;
11593 }
11594 }
11595 }
11596 }
11597
11598 // Check for circular reference only. This can happen when the object is only
11599 // referenced from mirrors and has a circular reference in which case the
11600 // object is not really alive and would have been garbage collected if not
11601 // referenced from the mirror.
11602 if (count == 1 && last == target) {
11603 count = 0;
11604 }
11605
11606 // Return the number of referencing objects found.
11607 return count;
11608}
11609
11610
11611// Scan the heap for objects with direct references to an object
11612// args[0]: the object to find references to
11613// args[1]: constructor function for instances to exclude (Mirror)
11614// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011615RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011616 ASSERT(args.length() == 3);
11617
11618 // First perform a full GC in order to avoid references from dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011619 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011620
11621 // Check parameters.
11622 CONVERT_CHECKED(JSObject, target, args[0]);
11623 Object* instance_filter = args[1];
11624 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
11625 instance_filter->IsJSObject());
11626 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
11627 RUNTIME_ASSERT(max_references >= 0);
11628
11629 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011630 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011631 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011632 JSFunction* arguments_function =
11633 JSFunction::cast(arguments_boilerplate->map()->constructor());
11634
11635 // Get the number of referencing objects.
11636 int count;
11637 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011638 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011639
11640 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011641 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011642 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011643 if (!maybe_object->ToObject(&object)) return maybe_object;
11644 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011645 FixedArray* instances = FixedArray::cast(object);
11646
11647 // Fill the referencing objects.
11648 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011649 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011650
11651 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011652 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011653 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11654 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011655 if (!maybe_result->ToObject(&result)) return maybe_result;
11656 }
11657 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011658 return result;
11659}
11660
11661
11662// Helper function used by Runtime_DebugConstructedBy below.
11663static int DebugConstructedBy(JSFunction* constructor, int max_references,
11664 FixedArray* instances, int instances_size) {
11665 AssertNoAllocation no_alloc;
11666
11667 // Iterate the heap.
11668 int count = 0;
11669 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011670 HeapObject* heap_obj = NULL;
11671 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011672 (max_references == 0 || count < max_references)) {
11673 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011674 if (heap_obj->IsJSObject()) {
11675 JSObject* obj = JSObject::cast(heap_obj);
11676 if (obj->map()->constructor() == constructor) {
11677 // Valid reference found add to instance array if supplied an update
11678 // count.
11679 if (instances != NULL && count < instances_size) {
11680 instances->set(count, obj);
11681 }
11682 count++;
11683 }
11684 }
11685 }
11686
11687 // Return the number of referencing objects found.
11688 return count;
11689}
11690
11691
11692// Scan the heap for objects constructed by a specific function.
11693// args[0]: the constructor to find instances of
11694// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011695RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011696 ASSERT(args.length() == 2);
11697
11698 // First perform a full GC in order to avoid dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011699 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011700
11701 // Check parameters.
11702 CONVERT_CHECKED(JSFunction, constructor, args[0]);
11703 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
11704 RUNTIME_ASSERT(max_references >= 0);
11705
11706 // Get the number of referencing objects.
11707 int count;
11708 count = DebugConstructedBy(constructor, max_references, NULL, 0);
11709
11710 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011711 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011712 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011713 if (!maybe_object->ToObject(&object)) return maybe_object;
11714 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011715 FixedArray* instances = FixedArray::cast(object);
11716
11717 // Fill the referencing objects.
11718 count = DebugConstructedBy(constructor, max_references, instances, count);
11719
11720 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011721 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011722 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11723 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011724 if (!maybe_result->ToObject(&result)) return maybe_result;
11725 }
11726 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011727 return result;
11728}
11729
11730
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011731// Find the effective prototype object as returned by __proto__.
11732// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011733RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011734 ASSERT(args.length() == 1);
11735
11736 CONVERT_CHECKED(JSObject, obj, args[0]);
11737
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011738 // Use the __proto__ accessor.
11739 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011740}
11741
11742
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011743RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000011744 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011745 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011746 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011747}
11748
11749
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011750RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011751#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011752 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011753 ASSERT(args.length() == 1);
11754 // Get the function and make sure it is compiled.
11755 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011756 Handle<SharedFunctionInfo> shared(func->shared());
11757 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011758 return Failure::Exception();
11759 }
11760 func->code()->PrintLn();
11761#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011762 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011763}
ager@chromium.org9085a012009-05-11 19:22:57 +000011764
11765
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011766RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011767#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011768 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011769 ASSERT(args.length() == 1);
11770 // Get the function and make sure it is compiled.
11771 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011772 Handle<SharedFunctionInfo> shared(func->shared());
11773 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011774 return Failure::Exception();
11775 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011776 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011777#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011778 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011779}
11780
11781
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011782RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000011783 NoHandleAllocation ha;
11784 ASSERT(args.length() == 1);
11785
11786 CONVERT_CHECKED(JSFunction, f, args[0]);
11787 return f->shared()->inferred_name();
11788}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011789
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011790
11791static int FindSharedFunctionInfosForScript(Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011792 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011793 AssertNoAllocation no_allocations;
11794
11795 int counter = 0;
11796 int buffer_size = buffer->length();
11797 HeapIterator iterator;
11798 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
11799 ASSERT(obj != NULL);
11800 if (!obj->IsSharedFunctionInfo()) {
11801 continue;
11802 }
11803 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
11804 if (shared->script() != script) {
11805 continue;
11806 }
11807 if (counter < buffer_size) {
11808 buffer->set(counter, shared);
11809 }
11810 counter++;
11811 }
11812 return counter;
11813}
11814
11815// For a script finds all SharedFunctionInfo's in the heap that points
11816// to this script. Returns JSArray of SharedFunctionInfo wrapped
11817// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011818RUNTIME_FUNCTION(MaybeObject*,
11819 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011820 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011821 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011822 CONVERT_CHECKED(JSValue, script_value, args[0]);
11823
11824 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
11825
11826 const int kBufferSize = 32;
11827
11828 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011829 array = isolate->factory()->NewFixedArray(kBufferSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011830 int number = FindSharedFunctionInfosForScript(*script, *array);
11831 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011832 array = isolate->factory()->NewFixedArray(number);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011833 FindSharedFunctionInfosForScript(*script, *array);
11834 }
11835
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011836 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011837 result->set_length(Smi::FromInt(number));
11838
11839 LiveEdit::WrapSharedFunctionInfos(result);
11840
11841 return *result;
11842}
11843
11844// For a script calculates compilation information about all its functions.
11845// The script source is explicitly specified by the second argument.
11846// The source of the actual script is not used, however it is important that
11847// all generated code keeps references to this particular instance of script.
11848// Returns a JSArray of compilation infos. The array is ordered so that
11849// each function with all its descendant is always stored in a continues range
11850// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011851RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011852 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011853 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011854 CONVERT_CHECKED(JSValue, script, args[0]);
11855 CONVERT_ARG_CHECKED(String, source, 1);
11856 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
11857
11858 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
11859
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011860 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011861 return Failure::Exception();
11862 }
11863
11864 return result;
11865}
11866
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011867// Changes the source of the script to a new_source.
11868// If old_script_name is provided (i.e. is a String), also creates a copy of
11869// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011870RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011871 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011872 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011873 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
11874 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011875 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011876
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011877 CONVERT_CHECKED(Script, original_script_pointer,
11878 original_script_value->value());
11879 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011880
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011881 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
11882 new_source,
11883 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011884
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011885 if (old_script->IsScript()) {
11886 Handle<Script> script_handle(Script::cast(old_script));
11887 return *(GetScriptWrapper(script_handle));
11888 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011889 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011890 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011891}
11892
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011893
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011894RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011895 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011896 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011897 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
11898 return LiveEdit::FunctionSourceUpdated(shared_info);
11899}
11900
11901
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011902// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011903RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011904 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011905 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011906 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
11907 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
11908
ager@chromium.orgac091b72010-05-05 07:34:42 +000011909 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011910}
11911
11912// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011913RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011914 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011915 HandleScope scope(isolate);
11916 Handle<Object> function_object(args[0], isolate);
11917 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011918
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011919 if (function_object->IsJSValue()) {
11920 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
11921 if (script_object->IsJSValue()) {
11922 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011923 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011924 }
11925
11926 LiveEdit::SetFunctionScript(function_wrapper, script_object);
11927 } else {
11928 // Just ignore this. We may not have a SharedFunctionInfo for some functions
11929 // and we check it in this function.
11930 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011931
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011932 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011933}
11934
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011935
11936// In a code of a parent function replaces original function as embedded object
11937// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011938RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011939 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011940 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011941
11942 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
11943 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
11944 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
11945
11946 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
11947 subst_wrapper);
11948
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011949 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011950}
11951
11952
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011953// Updates positions of a shared function info (first parameter) according
11954// to script source change. Text change is described in second parameter as
11955// array of groups of 3 numbers:
11956// (change_begin, change_end, change_end_new_position).
11957// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011958RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011959 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011960 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011961 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
11962 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
11963
ager@chromium.orgac091b72010-05-05 07:34:42 +000011964 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011965}
11966
11967
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011968// For array of SharedFunctionInfo's (each wrapped in JSValue)
11969// checks that none of them have activations on stacks (of any thread).
11970// Returns array of the same length with corresponding results of
11971// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011972RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011973 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011974 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011975 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000011976 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011977
ager@chromium.org357bf652010-04-12 11:30:10 +000011978 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011979}
11980
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011981// Compares 2 strings line-by-line, then token-wise and returns diff in form
11982// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
11983// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011984RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011985 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011986 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011987 CONVERT_ARG_CHECKED(String, s1, 0);
11988 CONVERT_ARG_CHECKED(String, s2, 1);
11989
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011990 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011991}
11992
11993
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011994// A testing entry. Returns statement position which is the closest to
11995// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011996RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011997 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011998 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011999 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12000 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12001
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012002 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012003
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012004 if (code->kind() != Code::FUNCTION &&
12005 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012006 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012007 }
12008
12009 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012010 int closest_pc = 0;
12011 int distance = kMaxInt;
12012 while (!it.done()) {
12013 int statement_position = static_cast<int>(it.rinfo()->data());
12014 // Check if this break point is closer that what was previously found.
12015 if (source_position <= statement_position &&
12016 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012017 closest_pc =
12018 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012019 distance = statement_position - source_position;
12020 // Check whether we can't get any closer.
12021 if (distance == 0) break;
12022 }
12023 it.next();
12024 }
12025
12026 return Smi::FromInt(closest_pc);
12027}
12028
12029
ager@chromium.org357bf652010-04-12 11:30:10 +000012030// Calls specified function with or without entering the debugger.
12031// This is used in unit tests to run code as if debugger is entered or simply
12032// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012033RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012034 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012035 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000012036 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12037 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
12038
12039 Handle<Object> result;
12040 bool pending_exception;
12041 {
12042 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012043 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012044 &pending_exception);
12045 } else {
12046 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012047 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012048 &pending_exception);
12049 }
12050 }
12051 if (!pending_exception) {
12052 return *result;
12053 } else {
12054 return Failure::Exception();
12055 }
12056}
12057
12058
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012059// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012060RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012061 CONVERT_CHECKED(String, arg, args[0]);
12062 SmartPointer<char> flags =
12063 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12064 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012065 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012066}
12067
12068
12069// Performs a GC.
12070// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012071RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012072 isolate->heap()->CollectAllGarbage(true);
12073 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012074}
12075
12076
12077// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012078RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012079 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012080 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012081 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012082 }
12083 return Smi::FromInt(usage);
12084}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012085
12086
12087// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012088RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012089#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012090 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012091#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012092 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012093#endif
12094}
12095
12096
12097// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012098RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012099#ifdef LIVE_OBJECT_LIST
12100 return LiveObjectList::Capture();
12101#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012102 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012103#endif
12104}
12105
12106
12107// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012108RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012109#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012110 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012111 bool success = LiveObjectList::Delete(id);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012112 return success ? isolate->heap()->true_value() :
12113 isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012114#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012115 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012116#endif
12117}
12118
12119
12120// Generates the response to a debugger request for a dump of the objects
12121// contained in the difference between the captured live object lists
12122// specified by id1 and id2.
12123// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12124// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012125RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012126#ifdef LIVE_OBJECT_LIST
12127 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012128 CONVERT_SMI_ARG_CHECKED(id1, 0);
12129 CONVERT_SMI_ARG_CHECKED(id2, 1);
12130 CONVERT_SMI_ARG_CHECKED(start, 2);
12131 CONVERT_SMI_ARG_CHECKED(count, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012132 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
12133 EnterDebugger enter_debugger;
12134 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12135#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012136 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012137#endif
12138}
12139
12140
12141// Gets the specified object as requested by the debugger.
12142// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012143RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012144#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012145 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012146 Object* result = LiveObjectList::GetObj(obj_id);
12147 return result;
12148#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012149 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012150#endif
12151}
12152
12153
12154// Gets the obj id for the specified address if valid.
12155// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012156RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012157#ifdef LIVE_OBJECT_LIST
12158 HandleScope scope;
12159 CONVERT_ARG_CHECKED(String, address, 0);
12160 Object* result = LiveObjectList::GetObjId(address);
12161 return result;
12162#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012163 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012164#endif
12165}
12166
12167
12168// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012169RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012170#ifdef LIVE_OBJECT_LIST
12171 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012172 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012173 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12174 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12175 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12176 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
12177 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
12178
12179 Handle<JSObject> instance_filter;
12180 if (args[1]->IsJSObject()) {
12181 instance_filter = args.at<JSObject>(1);
12182 }
12183 bool verbose = false;
12184 if (args[2]->IsBoolean()) {
12185 verbose = args[2]->IsTrue();
12186 }
12187 int start = 0;
12188 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012189 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012190 }
12191 int limit = Smi::kMaxValue;
12192 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012193 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012194 }
12195
12196 return LiveObjectList::GetObjRetainers(obj_id,
12197 instance_filter,
12198 verbose,
12199 start,
12200 limit,
12201 filter_obj);
12202#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012203 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012204#endif
12205}
12206
12207
12208// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012209RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012210#ifdef LIVE_OBJECT_LIST
12211 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012212 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
12213 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012214 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
12215
12216 Handle<JSObject> instance_filter;
12217 if (args[2]->IsJSObject()) {
12218 instance_filter = args.at<JSObject>(2);
12219 }
12220
12221 Object* result =
12222 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
12223 return result;
12224#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012225 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012226#endif
12227}
12228
12229
12230// Generates the response to a debugger request for a list of all
12231// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012232RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012233#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012234 CONVERT_SMI_ARG_CHECKED(start, 0);
12235 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012236 return LiveObjectList::Info(start, count);
12237#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012238 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012239#endif
12240}
12241
12242
12243// Gets a dump of the specified object as requested by the debugger.
12244// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012245RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012246#ifdef LIVE_OBJECT_LIST
12247 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012248 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012249 Object* result = LiveObjectList::PrintObj(obj_id);
12250 return result;
12251#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012252 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012253#endif
12254}
12255
12256
12257// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012258RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012259#ifdef LIVE_OBJECT_LIST
12260 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012261 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012262#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012263 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012264#endif
12265}
12266
12267
12268// Generates the response to a debugger request for a summary of the types
12269// of objects in the difference between the captured live object lists
12270// specified by id1 and id2.
12271// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12272// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012273RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012274#ifdef LIVE_OBJECT_LIST
12275 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012276 CONVERT_SMI_ARG_CHECKED(id1, 0);
12277 CONVERT_SMI_ARG_CHECKED(id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012278 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
12279
12280 EnterDebugger enter_debugger;
12281 return LiveObjectList::Summarize(id1, id2, filter_obj);
12282#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012283 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012284#endif
12285}
12286
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012287#endif // ENABLE_DEBUGGER_SUPPORT
12288
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012289
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012290RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012291 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012292 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012293 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012294}
12295
12296
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012297RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012298 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012299 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012300 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012301}
12302
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012303
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012304// Finds the script object from the script data. NOTE: This operation uses
12305// heap traversal to find the function generated for the source position
12306// for the requested break point. For lazily compiled functions several heap
12307// traversals might be required rendering this operation as a rather slow
12308// operation. However for setting break points which is normally done through
12309// some kind of user interaction the performance is not crucial.
12310static Handle<Object> Runtime_GetScriptFromScriptName(
12311 Handle<String> script_name) {
12312 // Scan the heap for Script objects to find the script with the requested
12313 // script data.
12314 Handle<Script> script;
12315 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012316 HeapObject* obj = NULL;
12317 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012318 // If a script is found check if it has the script data requested.
12319 if (obj->IsScript()) {
12320 if (Script::cast(obj)->name()->IsString()) {
12321 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
12322 script = Handle<Script>(Script::cast(obj));
12323 }
12324 }
12325 }
12326 }
12327
12328 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012329 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012330
12331 // Return the script found.
12332 return GetScriptWrapper(script);
12333}
12334
12335
12336// Get the script object from script data. NOTE: Regarding performance
12337// see the NOTE for GetScriptFromScriptData.
12338// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012339RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012340 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012341
12342 ASSERT(args.length() == 1);
12343
12344 CONVERT_CHECKED(String, script_name, args[0]);
12345
12346 // Find the requested script.
12347 Handle<Object> result =
12348 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
12349 return *result;
12350}
12351
12352
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012353// Determines whether the given stack frame should be displayed in
12354// a stack trace. The caller is the error constructor that asked
12355// for the stack trace to be collected. The first time a construct
12356// call to this function is encountered it is skipped. The seen_caller
12357// in/out parameter is used to remember if the caller has been seen
12358// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012359static bool ShowFrameInStackTrace(StackFrame* raw_frame,
12360 Object* caller,
12361 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012362 // Only display JS frames.
12363 if (!raw_frame->is_java_script())
12364 return false;
12365 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
12366 Object* raw_fun = frame->function();
12367 // Not sure when this can happen but skip it just in case.
12368 if (!raw_fun->IsJSFunction())
12369 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012370 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012371 *seen_caller = true;
12372 return false;
12373 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012374 // Skip all frames until we've seen the caller.
12375 if (!(*seen_caller)) return false;
12376 // Also, skip the most obvious builtin calls. We recognize builtins
12377 // as (1) functions called with the builtins object as the receiver and
12378 // as (2) functions from native scripts called with undefined as the
12379 // receiver (direct calls to helper functions in the builtins
12380 // code). Some builtin calls (such as Number.ADD which is invoked
12381 // using 'call') are very difficult to recognize so we're leaving
12382 // them in for now.
12383 if (frame->receiver()->IsJSBuiltinsObject()) {
12384 return false;
12385 }
12386 JSFunction* fun = JSFunction::cast(raw_fun);
12387 Object* raw_script = fun->shared()->script();
12388 if (frame->receiver()->IsUndefined() && raw_script->IsScript()) {
12389 int script_type = Script::cast(raw_script)->type()->value();
12390 return script_type != Script::TYPE_NATIVE;
12391 }
12392 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012393}
12394
12395
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012396// Collect the raw data for a stack trace. Returns an array of 4
12397// element segments each containing a receiver, function, code and
12398// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012399RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012400 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012401 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012402 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
12403
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012404 HandleScope scope(isolate);
12405 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012406
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000012407 limit = Max(limit, 0); // Ensure that limit is not negative.
12408 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012409 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012410 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012411
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012412 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012413 // If the caller parameter is a function we skip frames until we're
12414 // under it before starting to collect.
12415 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012416 int cursor = 0;
12417 int frames_seen = 0;
12418 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012419 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012420 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012421 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012422 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012423 // Set initial size to the maximum inlining level + 1 for the outermost
12424 // function.
12425 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012426 frame->Summarize(&frames);
12427 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012428 if (cursor + 4 > elements->length()) {
12429 int new_capacity = JSObject::NewElementsCapacity(elements->length());
12430 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012431 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012432 for (int i = 0; i < cursor; i++) {
12433 new_elements->set(i, elements->get(i));
12434 }
12435 elements = new_elements;
12436 }
12437 ASSERT(cursor + 4 <= elements->length());
12438
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012439 Handle<Object> recv = frames[i].receiver();
12440 Handle<JSFunction> fun = frames[i].function();
12441 Handle<Code> code = frames[i].code();
12442 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012443 elements->set(cursor++, *recv);
12444 elements->set(cursor++, *fun);
12445 elements->set(cursor++, *code);
12446 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012447 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012448 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012449 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012450 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012451 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012452 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012453 return *result;
12454}
12455
12456
ager@chromium.org3811b432009-10-28 14:53:37 +000012457// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012458RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000012459 ASSERT_EQ(args.length(), 0);
12460
12461 NoHandleAllocation ha;
12462
12463 const char* version_string = v8::V8::GetVersion();
12464
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012465 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
12466 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000012467}
12468
12469
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012470RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012471 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012472 OS::PrintError("abort: %s\n",
12473 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012474 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012475 OS::Abort();
12476 UNREACHABLE();
12477 return NULL;
12478}
12479
12480
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012481RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012482 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012483 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012484 Object* key = args[1];
12485
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012486 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012487 Object* o = cache->get(finger_index);
12488 if (o == key) {
12489 // The fastest case: hit the same place again.
12490 return cache->get(finger_index + 1);
12491 }
12492
12493 for (int i = finger_index - 2;
12494 i >= JSFunctionResultCache::kEntriesIndex;
12495 i -= 2) {
12496 o = cache->get(i);
12497 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012498 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012499 return cache->get(i + 1);
12500 }
12501 }
12502
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012503 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012504 ASSERT(size <= cache->length());
12505
12506 for (int i = size - 2; i > finger_index; i -= 2) {
12507 o = cache->get(i);
12508 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012509 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012510 return cache->get(i + 1);
12511 }
12512 }
12513
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012514 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012515 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012516
12517 Handle<JSFunctionResultCache> cache_handle(cache);
12518 Handle<Object> key_handle(key);
12519 Handle<Object> value;
12520 {
12521 Handle<JSFunction> factory(JSFunction::cast(
12522 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
12523 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012524 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012525 // This handle is nor shared, nor used later, so it's safe.
12526 Object** argv[] = { key_handle.location() };
12527 bool pending_exception = false;
12528 value = Execution::Call(factory,
12529 receiver,
12530 1,
12531 argv,
12532 &pending_exception);
12533 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012534 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012535
12536#ifdef DEBUG
12537 cache_handle->JSFunctionResultCacheVerify();
12538#endif
12539
12540 // Function invocation may have cleared the cache. Reread all the data.
12541 finger_index = cache_handle->finger_index();
12542 size = cache_handle->size();
12543
12544 // If we have spare room, put new data into it, otherwise evict post finger
12545 // entry which is likely to be the least recently used.
12546 int index = -1;
12547 if (size < cache_handle->length()) {
12548 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
12549 index = size;
12550 } else {
12551 index = finger_index + JSFunctionResultCache::kEntrySize;
12552 if (index == cache_handle->length()) {
12553 index = JSFunctionResultCache::kEntriesIndex;
12554 }
12555 }
12556
12557 ASSERT(index % 2 == 0);
12558 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
12559 ASSERT(index < cache_handle->length());
12560
12561 cache_handle->set(index, *key_handle);
12562 cache_handle->set(index + 1, *value);
12563 cache_handle->set_finger_index(index);
12564
12565#ifdef DEBUG
12566 cache_handle->JSFunctionResultCacheVerify();
12567#endif
12568
12569 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012570}
12571
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012572
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012573RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012574 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012575 CONVERT_ARG_CHECKED(String, type, 0);
12576 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012577 return *isolate->factory()->NewJSMessageObject(
12578 type,
12579 arguments,
12580 0,
12581 0,
12582 isolate->factory()->undefined_value(),
12583 isolate->factory()->undefined_value(),
12584 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012585}
12586
12587
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012588RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012589 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12590 return message->type();
12591}
12592
12593
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012594RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012595 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12596 return message->arguments();
12597}
12598
12599
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012600RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012601 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12602 return Smi::FromInt(message->start_position());
12603}
12604
12605
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012606RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012607 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12608 return message->script();
12609}
12610
12611
kasper.lund44510672008-07-25 07:37:58 +000012612#ifdef DEBUG
12613// ListNatives is ONLY used by the fuzz-natives.js in debug mode
12614// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012615RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000012616 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012617 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012618#define COUNT_ENTRY(Name, argc, ressize) + 1
12619 int entry_count = 0
12620 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
12621 INLINE_FUNCTION_LIST(COUNT_ENTRY)
12622 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
12623#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012624 Factory* factory = isolate->factory();
12625 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012626 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012627 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000012628#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012629 { \
12630 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012631 Handle<String> name; \
12632 /* Inline runtime functions have an underscore in front of the name. */ \
12633 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012634 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012635 Vector<const char>("_" #Name, StrLength("_" #Name))); \
12636 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012637 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012638 Vector<const char>(#Name, StrLength(#Name))); \
12639 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012640 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012641 pair_elements->set(0, *name); \
12642 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012643 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012644 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012645 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012646 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012647 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012648 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012649 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012650 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012651#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012652 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012653 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012654 return *result;
12655}
kasper.lund44510672008-07-25 07:37:58 +000012656#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012657
12658
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012659RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012660 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012661 CONVERT_CHECKED(String, format, args[0]);
12662 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012663 Vector<const char> chars = format->ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012664 LOGGER->LogRuntime(chars, elms);
12665 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012666}
12667
12668
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012669RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012670 UNREACHABLE(); // implemented as macro in the parser
12671 return NULL;
12672}
12673
12674
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012675#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
12676 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
12677 CONVERT_CHECKED(JSObject, obj, args[0]); \
12678 return isolate->heap()->ToBoolean(obj->Has##Name()); \
12679 }
12680
12681ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
12682ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
12683ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
12684ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
12685ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
12686ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
12687ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
12688ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
12689ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
12690ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
12691ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
12692ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
12693ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
12694
12695#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
12696
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012697// ----------------------------------------------------------------------------
12698// Implementation of Runtime
12699
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012700#define F(name, number_of_args, result_size) \
12701 { Runtime::k##name, Runtime::RUNTIME, #name, \
12702 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012703
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012704
12705#define I(name, number_of_args, result_size) \
12706 { Runtime::kInline##name, Runtime::INLINE, \
12707 "_" #name, NULL, number_of_args, result_size },
12708
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012709static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012710 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012711 INLINE_FUNCTION_LIST(I)
12712 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012713};
12714
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012715
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012716MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
12717 Object* dictionary) {
12718 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012719 ASSERT(dictionary != NULL);
12720 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
12721 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000012722 Object* name_symbol;
12723 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012724 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012725 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
12726 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012727 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012728 { MaybeObject* maybe_dictionary = string_dictionary->Add(
12729 String::cast(name_symbol),
12730 Smi::FromInt(i),
12731 PropertyDetails(NONE, NORMAL));
12732 if (!maybe_dictionary->ToObject(&dictionary)) {
12733 // Non-recoverable failure. Calling code must restart heap
12734 // initialization.
12735 return maybe_dictionary;
12736 }
12737 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012738 }
12739 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012740}
12741
12742
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012743const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
12744 Heap* heap = name->GetHeap();
12745 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012746 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012747 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012748 int function_index = Smi::cast(smi_index)->value();
12749 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012750 }
12751 return NULL;
12752}
12753
12754
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012755const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012756 return &(kIntrinsicFunctions[static_cast<int>(id)]);
12757}
12758
12759
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012760void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012761 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012762 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012763 if (failure->IsRetryAfterGC()) {
12764 // Try to do a garbage collection; ignore it if it fails. The C
12765 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012766 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012767 } else {
12768 // Handle last resort GC and make sure to allow future allocations
12769 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012770 isolate->counters()->gc_last_resort_from_js()->Increment();
12771 isolate->heap()->CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012772 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012773}
12774
12775
12776} } // namespace v8::internal